refactor: standardize modular architecture patterns

- Rename module definition variables to follow naming convention:
  - catalog/definition.py: module → catalog_module
  - checkout/definition.py: module → checkout_module
  - cart/definition.py: module → cart_module

- Add router attachment functions for lazy loading:
  - get_catalog_module_with_routers()
  - get_checkout_module_with_routers()
  - get_cart_module_with_routers()

- Move billing exceptions to exceptions.py:
  - Add backwards-compatible aliases (BillingServiceError, etc.)
  - Update billing_service.py to import from exceptions.py

- Standardize VendorEmailSettingsService DI pattern:
  - Change from db in __init__ to db as method parameter
  - Create singleton vendor_email_settings_service instance
  - Update routes and tests to use new pattern

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 18:40:03 +01:00
parent b769f5a047
commit a76128e016
11 changed files with 209 additions and 142 deletions

View File

@@ -19,10 +19,13 @@ from app.exceptions.base import (
__all__ = [
# Base billing exception
"BillingException",
"BillingServiceError", # Alias for backwards compatibility
# Subscription exceptions
"SubscriptionNotFoundException",
"NoActiveSubscriptionException",
"NoActiveSubscriptionError", # Alias for backwards compatibility
"SubscriptionNotCancelledException",
"SubscriptionNotCancelledError", # Alias for backwards compatibility
"SubscriptionAlreadyCancelledException",
# Tier exceptions
"TierNotFoundException",
@@ -30,8 +33,10 @@ __all__ = [
"TierLimitExceededException",
# Payment exceptions
"PaymentSystemNotConfiguredException",
"PaymentSystemNotConfiguredError", # Alias for backwards compatibility
"StripeNotConfiguredException",
"StripePriceNotConfiguredException",
"StripePriceNotConfiguredError", # Alias for backwards compatibility
"PaymentFailedException",
# Webhook exceptions
"InvalidWebhookSignatureException",
@@ -57,6 +62,10 @@ class BillingException(BusinessLogicException):
super().__init__(message=message, error_code=error_code, details=details)
# Alias for backwards compatibility with billing_service.py
BillingServiceError = BillingException
# =============================================================================
# Subscription Exceptions
# =============================================================================
@@ -83,6 +92,10 @@ class NoActiveSubscriptionException(BusinessLogicException):
)
# Alias for backwards compatibility with billing_service.py
NoActiveSubscriptionError = NoActiveSubscriptionException
class SubscriptionNotCancelledException(BusinessLogicException):
"""Raised when trying to reactivate a subscription that is not cancelled."""
@@ -93,6 +106,10 @@ class SubscriptionNotCancelledException(BusinessLogicException):
)
# Alias for backwards compatibility with billing_service.py
SubscriptionNotCancelledError = SubscriptionNotCancelledException
class SubscriptionAlreadyCancelledException(BusinessLogicException):
"""Raised when trying to cancel an already cancelled subscription."""
@@ -163,6 +180,10 @@ class PaymentSystemNotConfiguredException(ServiceUnavailableException):
super().__init__(message="Payment system not configured")
# Alias for backwards compatibility with billing_service.py
PaymentSystemNotConfiguredError = PaymentSystemNotConfiguredException
class StripeNotConfiguredException(BillingException):
"""Raised when Stripe is not configured."""
@@ -185,6 +206,10 @@ class StripePriceNotConfiguredException(BusinessLogicException):
self.tier_code = tier_code
# Alias for backwards compatibility with billing_service.py
StripePriceNotConfiguredError = StripePriceNotConfiguredException
class PaymentFailedException(BillingException):
"""Raised when a payment fails."""

View File

@@ -20,6 +20,8 @@ from app.modules.billing.services.admin_subscription_service import (
from app.modules.billing.services.billing_service import (
BillingService,
billing_service,
)
from app.modules.billing.exceptions import (
BillingServiceError,
PaymentSystemNotConfiguredError,
TierNotFoundError,

View File

@@ -23,54 +23,19 @@ from app.modules.billing.models import (
VendorAddOn,
VendorSubscription,
)
from app.modules.billing.exceptions import (
BillingServiceError,
NoActiveSubscriptionError,
PaymentSystemNotConfiguredError,
StripePriceNotConfiguredError,
SubscriptionNotCancelledError,
TierNotFoundError,
)
from app.modules.tenancy.models import Vendor
logger = logging.getLogger(__name__)
class BillingServiceError(Exception):
"""Base exception for billing service errors."""
pass
class PaymentSystemNotConfiguredError(BillingServiceError):
"""Raised when Stripe is not configured."""
def __init__(self):
super().__init__("Payment system not configured")
class TierNotFoundError(BillingServiceError):
"""Raised when a tier is not found."""
def __init__(self, tier_code: str):
self.tier_code = tier_code
super().__init__(f"Tier '{tier_code}' not found")
class StripePriceNotConfiguredError(BillingServiceError):
"""Raised when Stripe price is not configured for a tier."""
def __init__(self, tier_code: str):
self.tier_code = tier_code
super().__init__(f"Stripe price not configured for tier '{tier_code}'")
class NoActiveSubscriptionError(BillingServiceError):
"""Raised when no active subscription exists."""
def __init__(self):
super().__init__("No active subscription found")
class SubscriptionNotCancelledError(BillingServiceError):
"""Raised when trying to reactivate a non-cancelled subscription."""
def __init__(self):
super().__init__("Subscription is not cancelled")
class BillingService:
"""Service for billing operations."""