"""
Custom exceptions for Odoo MCP operations.
Provides a structured hierarchy of exceptions for different error types.
"""
from __future__ import annotations
class OdooError(Exception):
"""Base exception for all Odoo-related errors."""
def __init__(self, message: str, details: dict | None = None):
self.message = message
self.details = details or {}
super().__init__(message)
def __str__(self) -> str:
if self.details:
return f"{self.message} - Details: {self.details}"
return self.message
class OdooConnectionError(OdooError):
"""Raised when connection to Odoo fails."""
def __init__(self, message: str = "Failed to connect to Odoo", details: dict | None = None):
super().__init__(message, details)
class OdooAuthenticationError(OdooError):
"""Raised when authentication to Odoo fails."""
def __init__(self, message: str = "Authentication failed", details: dict | None = None):
super().__init__(message, details)
class OdooValidationError(OdooError):
"""Raised when input validation fails."""
def __init__(self, message: str, field: str | None = None, details: dict | None = None):
self.field = field
details = details or {}
if field:
details["field"] = field
super().__init__(message, details)
class OdooNotFoundError(OdooError):
"""Raised when a requested record is not found."""
def __init__(self, model: str, record_id: int, details: dict | None = None):
self.model = model
self.record_id = record_id
details = details or {}
details.update({"model": model, "record_id": record_id})
super().__init__(f"{model} with ID {record_id} not found", details)
class OdooPermissionError(OdooError):
"""Raised when user lacks permission for an operation."""
def __init__(self, operation: str, model: str | None = None, details: dict | None = None):
self.operation = operation
self.model = model
details = details or {}
details["operation"] = operation
if model:
details["model"] = model
message = f"Permission denied for operation: {operation}"
if model:
message += f" on {model}"
super().__init__(message, details)