# app/exceptions/billing.py """ Billing and subscription related exceptions. This module provides exceptions for: - Payment system configuration issues - Subscription management errors - Tier-related errors """ from typing import Any from .base import BusinessLogicException, ResourceNotFoundException, ServiceUnavailableException class PaymentSystemNotConfiguredException(ServiceUnavailableException): """Raised when the payment system (Stripe) is not configured.""" def __init__(self): super().__init__(message="Payment system not configured") class TierNotFoundException(ResourceNotFoundException): """Raised when a subscription tier is not found.""" def __init__(self, tier_code: str): super().__init__( resource_type="SubscriptionTier", identifier=tier_code, message=f"Subscription tier '{tier_code}' not found", error_code="TIER_NOT_FOUND", ) self.tier_code = tier_code class StripePriceNotConfiguredException(BusinessLogicException): """Raised when Stripe price is not configured for a tier.""" def __init__(self, tier_code: str): super().__init__( message=f"Stripe price not configured for tier '{tier_code}'", error_code="STRIPE_PRICE_NOT_CONFIGURED", details={"tier_code": tier_code}, ) self.tier_code = tier_code class NoActiveSubscriptionException(BusinessLogicException): """Raised when no active subscription exists for an operation that requires one.""" def __init__(self, message: str = "No active subscription found"): super().__init__( message=message, error_code="NO_ACTIVE_SUBSCRIPTION", ) class SubscriptionNotCancelledException(BusinessLogicException): """Raised when trying to reactivate a subscription that is not cancelled.""" def __init__(self): super().__init__( message="Subscription is not cancelled", error_code="SUBSCRIPTION_NOT_CANCELLED", ) class SubscriptionAlreadyCancelledException(BusinessLogicException): """Raised when trying to cancel an already cancelled subscription.""" def __init__(self): super().__init__( message="Subscription is already cancelled", error_code="SUBSCRIPTION_ALREADY_CANCELLED", ) class InvalidWebhookSignatureException(BusinessLogicException): """Raised when Stripe webhook signature verification fails.""" def __init__(self, message: str = "Invalid webhook signature"): super().__init__( message=message, error_code="INVALID_WEBHOOK_SIGNATURE", ) class WebhookMissingSignatureException(BusinessLogicException): """Raised when Stripe webhook is missing the signature header.""" def __init__(self): super().__init__( message="Missing Stripe-Signature header", error_code="WEBHOOK_MISSING_SIGNATURE", )