from typing import Any, List, Optional from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app import crud, models, schemas from app.api import deps router = APIRouter() @router.get("/", response_model=List[schemas.Product]) def read_products( db: Session = Depends(deps.get_db), skip: int = 0, limit: int = 100, category_id: Optional[int] = None, supplier_id: Optional[int] = None, low_stock: bool = False, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Retrieve products. """ if category_id: products = crud.product.get_by_category( db, category_id=category_id, skip=skip, limit=limit ) elif supplier_id: products = crud.product.get_by_supplier( db, supplier_id=supplier_id, skip=skip, limit=limit ) elif low_stock: products = crud.product.get_low_stock_products(db, skip=skip, limit=limit) else: products = crud.product.get_multi(db, skip=skip, limit=limit) return products @router.post("/", response_model=schemas.Product) def create_product( *, db: Session = Depends(deps.get_db), product_in: schemas.ProductCreate, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Create new product. """ # Check if SKU already exists product = crud.product.get_by_sku(db, sku=product_in.sku) if product: raise HTTPException( status_code=400, detail="The product with this SKU already exists in the system.", ) # Check if barcode already exists if provided if product_in.barcode: product = crud.product.get_by_barcode(db, barcode=product_in.barcode) if product: raise HTTPException( status_code=400, detail="The product with this barcode already exists in the system.", ) # Check if category exists if provided if product_in.category_id: category = crud.category.get(db, id=product_in.category_id) if not category: raise HTTPException( status_code=404, detail="The category does not exist in the system.", ) # Check if supplier exists if provided if product_in.supplier_id: supplier = crud.supplier.get(db, id=product_in.supplier_id) if not supplier: raise HTTPException( status_code=404, detail="The supplier does not exist in the system.", ) product = crud.product.create(db, obj_in=product_in) return product @router.get("/{product_id}", response_model=schemas.Product) def read_product( *, db: Session = Depends(deps.get_db), product_id: int, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Get product by ID. """ product = crud.product.get(db, id=product_id) if not product: raise HTTPException(status_code=404, detail="Product not found") return product @router.put("/{product_id}", response_model=schemas.Product) def update_product( *, db: Session = Depends(deps.get_db), product_id: int, product_in: schemas.ProductUpdate, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Update a product. """ product = crud.product.get(db, id=product_id) if not product: raise HTTPException(status_code=404, detail="Product not found") # If SKU is being updated, check for duplicates if product_in.sku and product_in.sku != product.sku: existing_product = crud.product.get_by_sku(db, sku=product_in.sku) if existing_product: raise HTTPException( status_code=400, detail="The product with this SKU already exists in the system.", ) # If barcode is being updated, check for duplicates if product_in.barcode and product_in.barcode != product.barcode: existing_product = crud.product.get_by_barcode(db, barcode=product_in.barcode) if existing_product: raise HTTPException( status_code=400, detail="The product with this barcode already exists in the system.", ) # Check if category exists if provided if product_in.category_id: category = crud.category.get(db, id=product_in.category_id) if not category: raise HTTPException( status_code=404, detail="The category does not exist in the system.", ) # Check if supplier exists if provided if product_in.supplier_id: supplier = crud.supplier.get(db, id=product_in.supplier_id) if not supplier: raise HTTPException( status_code=404, detail="The supplier does not exist in the system.", ) product = crud.product.update(db, db_obj=product, obj_in=product_in) return product @router.delete("/{product_id}", response_model=schemas.Product) def delete_product( *, db: Session = Depends(deps.get_db), product_id: int, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Delete a product. """ product = crud.product.get(db, id=product_id) if not product: raise HTTPException(status_code=404, detail="Product not found") product = crud.product.remove(db, id=product_id) return product @router.post("/{product_id}/adjust", response_model=schemas.Product) def adjust_product_quantity( *, db: Session = Depends(deps.get_db), product_id: int, adjustment: schemas.ProductAdjustment, current_user: models.User = Depends(deps.get_current_active_user), ) -> Any: """ Adjust product quantity and create an inventory transaction. """ product = crud.product.get(db, id=product_id) if not product: raise HTTPException(status_code=404, detail="Product not found") # Create an inventory adjustment transaction transaction_in = schemas.InventoryTransactionCreate( transaction_type=models.inventory_transaction.TransactionType.ADJUSTMENT, quantity=adjustment.quantity, unit_price=product.unit_price, notes=adjustment.notes, product_id=product_id, ) # Create the transaction and update the product quantity crud.inventory_transaction.create_with_product_update( db, obj_in=transaction_in, current_user_id=current_user.id ) # Return the updated product db.refresh(product) return product