# app/exceptions/invoice.py """ Invoice-related exceptions. This module provides exception classes for invoice operations including: - Invoice not found errors - Invoice settings validation - PDF generation errors - Invoice status transitions """ from typing import Any from .base import BusinessLogicException, ResourceNotFoundException, WizamartException class InvoiceNotFoundException(ResourceNotFoundException): """Raised when an invoice is not found.""" def __init__(self, invoice_id: int | str): super().__init__( resource_type="Invoice", identifier=str(invoice_id), error_code="INVOICE_NOT_FOUND", ) class InvoiceSettingsNotFoundException(ResourceNotFoundException): """Raised when invoice settings are not found for a vendor.""" def __init__(self, vendor_id: int): super().__init__( resource_type="InvoiceSettings", identifier=str(vendor_id), message="Invoice settings not found. Create settings first.", error_code="INVOICE_SETTINGS_NOT_FOUND", ) class InvoiceSettingsAlreadyExistException(WizamartException): """Raised when trying to create invoice settings that already exist.""" def __init__(self, vendor_id: int): super().__init__( message=f"Invoice settings already exist for vendor {vendor_id}", error_code="INVOICE_SETTINGS_ALREADY_EXIST", status_code=409, details={"vendor_id": vendor_id}, ) class InvoiceValidationException(BusinessLogicException): """Raised when invoice data validation fails.""" def __init__(self, message: str, details: dict[str, Any] | None = None): super().__init__( message=message, error_code="INVOICE_VALIDATION_ERROR", details=details, ) class InvoicePDFGenerationException(WizamartException): """Raised when PDF generation fails.""" def __init__(self, invoice_id: int, reason: str): super().__init__( message=f"Failed to generate PDF for invoice {invoice_id}: {reason}", error_code="INVOICE_PDF_GENERATION_FAILED", status_code=500, details={"invoice_id": invoice_id, "reason": reason}, ) class InvoicePDFNotFoundException(ResourceNotFoundException): """Raised when invoice PDF file is not found.""" def __init__(self, invoice_id: int): super().__init__( resource_type="InvoicePDF", identifier=str(invoice_id), message="PDF file not found. Generate the PDF first.", error_code="INVOICE_PDF_NOT_FOUND", ) class InvalidInvoiceStatusTransitionException(BusinessLogicException): """Raised when an invalid invoice status transition is attempted.""" def __init__( self, current_status: str, new_status: str, reason: str | None = None, ): message = f"Cannot change invoice status from '{current_status}' to '{new_status}'" if reason: message += f": {reason}" super().__init__( message=message, error_code="INVALID_INVOICE_STATUS_TRANSITION", details={ "current_status": current_status, "new_status": new_status, }, ) class OrderNotFoundException(ResourceNotFoundException): """Raised when an order for invoice creation is not found.""" def __init__(self, order_id: int): super().__init__( resource_type="Order", identifier=str(order_id), error_code="ORDER_NOT_FOUND_FOR_INVOICE", )