from fastapi import APIRouter, Depends, HTTPException, status from sqlmodel import Session, select from app.core.db import get_session from app.core.auth import require_any_access, require_write_access, require_admin from app.schemas.models import Product from app.schemas.schemas import ( ProductCreate, ProductUpdate, ProductResponse, UserResponse ) from typing import List router = APIRouter(prefix="/products", tags=["products"]) # Create Product @router.post("/", response_model=ProductResponse, status_code=status.HTTP_201_CREATED) def create_product( product: ProductCreate, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_write_access) ): """Create a new product (requires write access).""" # Check if product code already exists statement = select(Product).where(Product.product_code == product.product_code) existing_product = session.exec(statement).first() if existing_product: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Product with this code already exists" ) # Check if product name already exists statement = select(Product).where(Product.product_name == product.product_name) existing_product = session.exec(statement).first() if existing_product: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Product with this name already exists" ) # Create new product product_data = product.model_dump() db_product = Product(**product_data) session.add(db_product) session.commit() session.refresh(db_product) return db_product # Read all Products @router.get("/", response_model=List[ProductResponse]) def read_products( skip: int = 0, limit: int = 100, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_any_access) ): """Get all products (requires authentication).""" products = session.exec(select(Product).offset(skip).limit(limit)).all() return products # Read single Product by ID @router.get("/{product_id}", response_model=ProductResponse) def read_product( product_id: int, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_any_access) ): """Get specific product by ID (requires authentication).""" product = session.get(Product, product_id) if not product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found" ) return product # Read Product by code @router.get("/code/{product_code}", response_model=ProductResponse) def read_product_by_code( product_code: str, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_any_access) ): """Get specific product by code (requires authentication).""" statement = select(Product).where(Product.product_code == product_code) product = session.exec(statement).first() if not product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found" ) return product # Update Product @router.put("/{product_id}", response_model=ProductResponse) def update_product( product_id: int, product: ProductUpdate, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_write_access) ): """Update specific product (requires write access).""" db_product = session.get(Product, product_id) if not db_product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found" ) update_data = product.model_dump(exclude_unset=True) # Check for product code conflicts if updating code if "product_code" in update_data: statement = select(Product).where( Product.product_code == update_data["product_code"], Product.id != product_id ) existing_product = session.exec(statement).first() if existing_product: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Product with this code already exists" ) # Check for product name conflicts if updating name if "product_name" in update_data: statement = select(Product).where( Product.product_name == update_data["product_name"], Product.id != product_id ) existing_product = session.exec(statement).first() if existing_product: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Product with this name already exists" ) # Update product for key, value in update_data.items(): setattr(db_product, key, value) session.add(db_product) session.commit() session.refresh(db_product) return db_product # Delete Product @router.delete("/{product_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_product( product_id: int, session: Session = Depends(get_session), current_user: UserResponse = Depends(require_admin) ): """Delete specific product (admin only).""" product = session.get(Product, product_id) if not product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found" ) session.delete(product) session.commit() return None