Files
orion/app/modules/billing/exceptions.py
Samir Boulahtit 4f379b472b feat: complete billing module migration (Phase 5)
Migrates billing module to self-contained structure:
- Create app/modules/billing/services/ with subscription, stripe, admin services
- Create app/modules/billing/models/ re-exporting from central location
- Create app/modules/billing/schemas/ re-exporting from central location
- Create app/modules/billing/tasks/ with 4 scheduled Celery tasks
- Create app/modules/billing/exceptions.py with module-specific exceptions
- Update definition.py with is_self_contained=True and scheduled_tasks

Celery task migration:
- reset_period_counters -> billing module
- check_trial_expirations -> billing module
- sync_stripe_status -> billing module
- cleanup_stale_subscriptions -> billing module
- capture_capacity_snapshot remains in legacy (will go to monitoring)

Backward compatibility:
- Create re-exports in app/services/ for subscription, stripe, admin services
- Old import paths continue to work
- Update celery_config.py to use module-defined schedules

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 23:06:23 +01:00

84 lines
2.4 KiB
Python

# app/modules/billing/exceptions.py
"""
Billing module exceptions.
Custom exceptions for subscription, billing, and payment operations.
"""
from app.exceptions import BusinessLogicException, ResourceNotFoundException
class BillingException(BusinessLogicException):
"""Base exception for billing module errors."""
pass
class SubscriptionNotFoundException(ResourceNotFoundException):
"""Raised when a subscription is not found."""
def __init__(self, vendor_id: int):
super().__init__("Subscription", str(vendor_id))
class TierNotFoundException(ResourceNotFoundException):
"""Raised when a subscription tier is not found."""
def __init__(self, tier_code: str):
super().__init__("SubscriptionTier", tier_code)
class TierLimitExceededException(BillingException):
"""Raised when a tier limit is exceeded."""
def __init__(self, message: str, limit_type: str, current: int, limit: int):
super().__init__(message)
self.limit_type = limit_type
self.current = current
self.limit = limit
class FeatureNotAvailableException(BillingException):
"""Raised when a feature is not available in current tier."""
def __init__(self, feature: str, current_tier: str, required_tier: str):
message = f"Feature '{feature}' requires {required_tier} tier (current: {current_tier})"
super().__init__(message)
self.feature = feature
self.current_tier = current_tier
self.required_tier = required_tier
class StripeNotConfiguredException(BillingException):
"""Raised when Stripe is not configured."""
def __init__(self):
super().__init__("Stripe is not configured")
class PaymentFailedException(BillingException):
"""Raised when a payment fails."""
def __init__(self, message: str, stripe_error: str | None = None):
super().__init__(message)
self.stripe_error = stripe_error
class WebhookVerificationException(BillingException):
"""Raised when webhook signature verification fails."""
def __init__(self, message: str = "Invalid webhook signature"):
super().__init__(message)
__all__ = [
"BillingException",
"SubscriptionNotFoundException",
"TierNotFoundException",
"TierLimitExceededException",
"FeatureNotAvailableException",
"StripeNotConfiguredException",
"PaymentFailedException",
"WebhookVerificationException",
]