# app/modules/catalog/exceptions.py """ Catalog module exceptions. This module provides exception classes for catalog operations including: - Product management (CRUD) - Product validation - Product dependencies (inventory, orders) """ from app.exceptions.base import ( BusinessLogicException, ConflictException, ResourceNotFoundException, ValidationException, ) __all__ = [ "ProductNotFoundException", "ProductAlreadyExistsException", "ProductNotInCatalogException", "ProductNotActiveException", "InvalidProductDataException", "ProductValidationException", "CannotDeleteProductException", "CannotDeleteProductWithInventoryException", "CannotDeleteProductWithOrdersException", "ProductMediaException", ] class ProductNotFoundException(ResourceNotFoundException): """Raised when a product is not found in store catalog.""" def __init__(self, product_id: int, store_id: int | None = None): if store_id: message = f"Product with ID '{product_id}' not found in store {store_id} catalog" else: message = f"Product with ID '{product_id}' not found" super().__init__( resource_type="Product", identifier=str(product_id), message=message, error_code="PRODUCT_NOT_FOUND", ) self.details["product_id"] = product_id if store_id: self.details["store_id"] = store_id class ProductAlreadyExistsException(ConflictException): """Raised when trying to add a product that already exists.""" def __init__(self, store_id: int, identifier: str | int): super().__init__( message=f"Product '{identifier}' already exists in store {store_id} catalog", error_code="PRODUCT_ALREADY_EXISTS", details={ "store_id": store_id, "identifier": identifier, }, ) class ProductNotInCatalogException(ResourceNotFoundException): # noqa: MOD025 """Raised when trying to access a product that's not in store's catalog.""" def __init__(self, product_id: int, store_id: int): super().__init__( resource_type="Product", identifier=str(product_id), message=f"Product {product_id} is not in store {store_id} catalog", error_code="PRODUCT_NOT_IN_CATALOG", ) self.details["product_id"] = product_id self.details["store_id"] = store_id class ProductNotActiveException(BusinessLogicException): """Raised when trying to perform operations on inactive product.""" def __init__(self, product_id: int, store_id: int): super().__init__( message=f"Product {product_id} in store {store_id} catalog is not active", error_code="PRODUCT_NOT_ACTIVE", details={ "product_id": product_id, "store_id": store_id, }, ) class InvalidProductDataException(ValidationException): """Raised when product data is invalid.""" def __init__( self, message: str = "Invalid product data", field: str | None = None, details: dict | None = None, ): super().__init__( message=message, field=field, details=details, ) self.error_code = "INVALID_PRODUCT_DATA" class ProductValidationException(ValidationException): """Raised when product data validation fails.""" def __init__( self, message: str = "Product validation failed", field: str | None = None, validation_errors: dict | None = None, ): details = {} if validation_errors: details["validation_errors"] = validation_errors super().__init__( message=message, field=field, details=details, ) self.error_code = "PRODUCT_VALIDATION_FAILED" class CannotDeleteProductException(BusinessLogicException): # noqa: MOD025 """Raised when a product cannot be deleted due to dependencies.""" def __init__(self, product_id: int, reason: str, details: dict | None = None): super().__init__( message=f"Cannot delete product {product_id}: {reason}", error_code="CANNOT_DELETE_PRODUCT", details={"product_id": product_id, "reason": reason, **(details or {})}, ) class CannotDeleteProductWithInventoryException(BusinessLogicException): # noqa: MOD025 """Raised when trying to delete a product that has inventory.""" def __init__(self, product_id: int, inventory_count: int): super().__init__( message=f"Cannot delete product {product_id} - it has {inventory_count} inventory entries", error_code="CANNOT_DELETE_PRODUCT_WITH_INVENTORY", details={ "product_id": product_id, "inventory_count": inventory_count, }, ) class CannotDeleteProductWithOrdersException(BusinessLogicException): # noqa: MOD025 """Raised when trying to delete a product that has been ordered.""" def __init__(self, product_id: int, order_count: int): super().__init__( message=f"Cannot delete product {product_id} - it has {order_count} associated orders", error_code="CANNOT_DELETE_PRODUCT_WITH_ORDERS", details={ "product_id": product_id, "order_count": order_count, }, ) class ProductMediaException(BusinessLogicException): """Raised when there's an issue with product media.""" def __init__(self, product_id: int, message: str): super().__init__( message=message, error_code="PRODUCT_MEDIA_ERROR", details={"product_id": product_id}, )