137 lines
4.2 KiB
Python

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