# app/modules/inventory/exceptions.py """ Inventory module exceptions. This module provides exception classes for inventory operations including: - Inventory record management - Quantity validation - Location management """ from typing import Any from app.exceptions.base import ( BusinessLogicException, ResourceNotFoundException, ValidationException, ) __all__ = [ "InventoryNotFoundException", "InsufficientInventoryException", "InvalidInventoryOperationException", "InventoryValidationException", "NegativeInventoryException", "InvalidQuantityException", "LocationNotFoundException", ] class InventoryNotFoundException(ResourceNotFoundException): """Raised when inventory record is not found.""" def __init__(self, identifier: str, identifier_type: str = "ID"): if identifier_type.lower() == "gtin": message = f"No inventory found for GTIN '{identifier}'" else: message = ( f"Inventory record with {identifier_type} '{identifier}' not found" ) super().__init__( resource_type="Inventory", identifier=identifier, message=message, error_code="INVENTORY_NOT_FOUND", ) class InsufficientInventoryException(BusinessLogicException): """Raised when trying to remove more inventory than available.""" def __init__( self, gtin: str, location: str, requested: int, available: int, ): message = f"Insufficient inventory for GTIN '{gtin}' at '{location}'. Requested: {requested}, Available: {available}" super().__init__( message=message, error_code="INSUFFICIENT_INVENTORY", details={ "gtin": gtin, "location": location, "requested_quantity": requested, "available_quantity": available, }, ) class InvalidInventoryOperationException(ValidationException): """Raised when inventory operation is invalid.""" def __init__( self, message: str, operation: str | None = None, details: dict[str, Any] | None = None, ): if not details: details = {} if operation: details["operation"] = operation super().__init__( message=message, details=details, ) self.error_code = "INVALID_INVENTORY_OPERATION" class InventoryValidationException(ValidationException): """Raised when inventory data validation fails.""" def __init__( self, message: str = "Inventory validation failed", field: str | None = None, validation_errors: dict[str, str] | None = None, ): details = {} if validation_errors: details["validation_errors"] = validation_errors super().__init__( message=message, field=field, details=details, ) self.error_code = "INVENTORY_VALIDATION_FAILED" class NegativeInventoryException(BusinessLogicException): # noqa: MOD025 """Raised when inventory quantity would become negative.""" def __init__(self, gtin: str, location: str, resulting_quantity: int): message = f"Inventory operation would result in negative quantity ({resulting_quantity}) for GTIN '{gtin}' at '{location}'" super().__init__( message=message, error_code="NEGATIVE_INVENTORY_NOT_ALLOWED", details={ "gtin": gtin, "location": location, "resulting_quantity": resulting_quantity, }, ) class InvalidQuantityException(ValidationException): """Raised when quantity value is invalid.""" def __init__(self, quantity: Any, message: str = "Invalid quantity"): super().__init__( message=f"{message}: {quantity}", field="quantity", details={"quantity": quantity}, ) self.error_code = "INVALID_QUANTITY" class LocationNotFoundException(ResourceNotFoundException): # noqa: MOD025 """Raised when inventory location is not found.""" def __init__(self, location: str): super().__init__( resource_type="Location", identifier=location, message=f"Inventory location '{location}' not found", error_code="LOCATION_NOT_FOUND", )