import logging from typing import Any from fastapi import HTTPException, status from sqlalchemy.orm import Session from app.models.product import Product, ProductStatus logger = logging.getLogger(__name__) class InventoryService: """ Service for managing product inventory. """ @staticmethod def update_stock( db: Session, product_id: str, quantity_change: int, operation: str = "add" ) -> Product: """ Update the stock quantity of a product. Args: db: Database session product_id: Product ID quantity_change: Amount to change stock by (positive or negative) operation: "add" to increase stock, "subtract" to decrease Returns: Updated product object """ product = db.query(Product).filter(Product.id == product_id).first() if not product: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Product not found" ) if operation == "add": product.stock_quantity += quantity_change # If stock was 0 and now it's not, update status if product.stock_quantity > 0 and product.status == ProductStatus.OUT_OF_STOCK: product.status = ProductStatus.PUBLISHED elif operation == "subtract": if product.stock_quantity < quantity_change: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Cannot subtract {quantity_change} units. Only {product.stock_quantity} in stock." ) product.stock_quantity -= quantity_change # If stock is now 0, update status if product.stock_quantity == 0 and product.status == ProductStatus.PUBLISHED: product.status = ProductStatus.OUT_OF_STOCK else: raise ValueError(f"Invalid operation: {operation}. Must be 'add' or 'subtract'.") db.commit() db.refresh(product) logger.info(f"Updated stock for product {product.id}. New quantity: {product.stock_quantity}") return product @staticmethod def get_low_stock_products( db: Session, threshold: int = 5, category_id: str | None = None, seller_id: str | None = None ) -> list[Product]: """ Get products with low stock. Args: db: Database session threshold: Stock threshold to consider "low" category_id: Optional category ID to filter by seller_id: Optional seller ID to filter by Returns: List of products with low stock """ query = db.query(Product).filter(Product.stock_quantity <= threshold) if category_id: query = query.filter(Product.category_id == category_id) if seller_id: query = query.filter(Product.seller_id == seller_id) return query.all() @staticmethod def bulk_update_stock( db: Session, updates: list[dict[str, Any]] ) -> list[Product]: """ Update stock for multiple products at once. Args: db: Database session updates: List of dicts with product_id, quantity_change, and operation Returns: List of updated products """ updated_products = [] for update in updates: product_id = update.get('product_id') quantity_change = update.get('quantity_change', 0) operation = update.get('operation', 'add') if not product_id or not isinstance(quantity_change, int): logger.warning(f"Skipping invalid update: {update}") continue try: product = InventoryService.update_stock( db, product_id, quantity_change, operation ) updated_products.append(product) except Exception as e: logger.error(f"Error updating stock for product {product_id}: {str(e)}") return updated_products