django-cfg 1.2.22__py3-none-any.whl → 1.2.25__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/knowbase/tasks/archive_tasks.py +6 -6
  3. django_cfg/apps/knowbase/tasks/document_processing.py +3 -3
  4. django_cfg/apps/knowbase/tasks/external_data_tasks.py +2 -2
  5. django_cfg/apps/knowbase/tasks/maintenance.py +3 -3
  6. django_cfg/apps/payments/admin/__init__.py +23 -0
  7. django_cfg/apps/payments/admin/api_keys_admin.py +347 -0
  8. django_cfg/apps/payments/admin/balance_admin.py +434 -0
  9. django_cfg/apps/payments/admin/currencies_admin.py +186 -0
  10. django_cfg/apps/payments/admin/filters.py +259 -0
  11. django_cfg/apps/payments/admin/payments_admin.py +142 -0
  12. django_cfg/apps/payments/admin/subscriptions_admin.py +227 -0
  13. django_cfg/apps/payments/admin/tariffs_admin.py +199 -0
  14. django_cfg/apps/payments/config/__init__.py +65 -0
  15. django_cfg/apps/payments/config/module.py +70 -0
  16. django_cfg/apps/payments/config/providers.py +115 -0
  17. django_cfg/apps/payments/config/settings.py +96 -0
  18. django_cfg/apps/payments/config/utils.py +52 -0
  19. django_cfg/apps/payments/decorators.py +291 -0
  20. django_cfg/apps/payments/management/__init__.py +3 -0
  21. django_cfg/apps/payments/management/commands/README.md +178 -0
  22. django_cfg/apps/payments/management/commands/__init__.py +3 -0
  23. django_cfg/apps/payments/management/commands/currency_stats.py +323 -0
  24. django_cfg/apps/payments/management/commands/populate_currencies.py +246 -0
  25. django_cfg/apps/payments/management/commands/update_currencies.py +336 -0
  26. django_cfg/apps/payments/managers/currency_manager.py +65 -14
  27. django_cfg/apps/payments/middleware/api_access.py +294 -0
  28. django_cfg/apps/payments/middleware/rate_limiting.py +216 -0
  29. django_cfg/apps/payments/middleware/usage_tracking.py +296 -0
  30. django_cfg/apps/payments/migrations/0001_initial.py +125 -11
  31. django_cfg/apps/payments/models/__init__.py +18 -0
  32. django_cfg/apps/payments/models/api_keys.py +2 -2
  33. django_cfg/apps/payments/models/balance.py +2 -2
  34. django_cfg/apps/payments/models/base.py +16 -0
  35. django_cfg/apps/payments/models/events.py +2 -2
  36. django_cfg/apps/payments/models/payments.py +112 -2
  37. django_cfg/apps/payments/models/subscriptions.py +2 -2
  38. django_cfg/apps/payments/services/__init__.py +64 -7
  39. django_cfg/apps/payments/services/billing/__init__.py +8 -0
  40. django_cfg/apps/payments/services/cache/__init__.py +15 -0
  41. django_cfg/apps/payments/services/cache/base.py +30 -0
  42. django_cfg/apps/payments/services/cache/simple_cache.py +135 -0
  43. django_cfg/apps/payments/services/core/__init__.py +17 -0
  44. django_cfg/apps/payments/services/core/balance_service.py +447 -0
  45. django_cfg/apps/payments/services/core/fallback_service.py +432 -0
  46. django_cfg/apps/payments/services/core/payment_service.py +576 -0
  47. django_cfg/apps/payments/services/core/subscription_service.py +614 -0
  48. django_cfg/apps/payments/services/internal_types.py +297 -0
  49. django_cfg/apps/payments/services/middleware/__init__.py +8 -0
  50. django_cfg/apps/payments/services/monitoring/__init__.py +22 -0
  51. django_cfg/apps/payments/services/monitoring/api_schemas.py +222 -0
  52. django_cfg/apps/payments/services/monitoring/provider_health.py +372 -0
  53. django_cfg/apps/payments/services/providers/__init__.py +22 -0
  54. django_cfg/apps/payments/services/providers/base.py +137 -0
  55. django_cfg/apps/payments/services/providers/cryptapi.py +273 -0
  56. django_cfg/apps/payments/services/providers/cryptomus.py +310 -0
  57. django_cfg/apps/payments/services/providers/nowpayments.py +293 -0
  58. django_cfg/apps/payments/services/providers/registry.py +103 -0
  59. django_cfg/apps/payments/services/security/__init__.py +34 -0
  60. django_cfg/apps/payments/services/security/error_handler.py +637 -0
  61. django_cfg/apps/payments/services/security/payment_notifications.py +342 -0
  62. django_cfg/apps/payments/services/security/webhook_validator.py +475 -0
  63. django_cfg/apps/payments/services/validators/__init__.py +8 -0
  64. django_cfg/apps/payments/signals/__init__.py +13 -0
  65. django_cfg/apps/payments/signals/api_key_signals.py +160 -0
  66. django_cfg/apps/payments/signals/payment_signals.py +128 -0
  67. django_cfg/apps/payments/signals/subscription_signals.py +196 -0
  68. django_cfg/apps/payments/tasks/__init__.py +12 -0
  69. django_cfg/apps/payments/tasks/webhook_processing.py +177 -0
  70. django_cfg/apps/payments/urls.py +5 -5
  71. django_cfg/apps/payments/utils/__init__.py +45 -0
  72. django_cfg/apps/payments/utils/billing_utils.py +342 -0
  73. django_cfg/apps/payments/utils/config_utils.py +245 -0
  74. django_cfg/apps/payments/utils/middleware_utils.py +228 -0
  75. django_cfg/apps/payments/utils/validation_utils.py +94 -0
  76. django_cfg/apps/payments/views/payment_views.py +40 -2
  77. django_cfg/apps/payments/views/webhook_views.py +266 -0
  78. django_cfg/apps/payments/viewsets.py +65 -0
  79. django_cfg/apps/support/signals.py +16 -4
  80. django_cfg/apps/support/templates/support/chat/ticket_chat.html +1 -1
  81. django_cfg/cli/README.md +2 -2
  82. django_cfg/cli/commands/create_project.py +1 -1
  83. django_cfg/cli/commands/info.py +1 -1
  84. django_cfg/cli/main.py +1 -1
  85. django_cfg/cli/utils.py +5 -5
  86. django_cfg/core/config.py +18 -4
  87. django_cfg/models/payments.py +546 -0
  88. django_cfg/models/revolution.py +1 -1
  89. django_cfg/models/tasks.py +51 -2
  90. django_cfg/modules/base.py +12 -6
  91. django_cfg/modules/django_currency/README.md +104 -269
  92. django_cfg/modules/django_currency/__init__.py +99 -41
  93. django_cfg/modules/django_currency/clients/__init__.py +11 -0
  94. django_cfg/modules/django_currency/clients/coingecko_client.py +257 -0
  95. django_cfg/modules/django_currency/clients/yfinance_client.py +246 -0
  96. django_cfg/modules/django_currency/core/__init__.py +42 -0
  97. django_cfg/modules/django_currency/core/converter.py +169 -0
  98. django_cfg/modules/django_currency/core/exceptions.py +28 -0
  99. django_cfg/modules/django_currency/core/models.py +54 -0
  100. django_cfg/modules/django_currency/database/__init__.py +25 -0
  101. django_cfg/modules/django_currency/database/database_loader.py +507 -0
  102. django_cfg/modules/django_currency/utils/__init__.py +9 -0
  103. django_cfg/modules/django_currency/utils/cache.py +92 -0
  104. django_cfg/modules/django_email.py +42 -4
  105. django_cfg/modules/django_unfold/dashboard.py +20 -0
  106. django_cfg/registry/core.py +10 -0
  107. django_cfg/template_archive/__init__.py +0 -0
  108. django_cfg/template_archive/django_sample.zip +0 -0
  109. {django_cfg-1.2.22.dist-info → django_cfg-1.2.25.dist-info}/METADATA +11 -6
  110. {django_cfg-1.2.22.dist-info → django_cfg-1.2.25.dist-info}/RECORD +113 -50
  111. django_cfg/apps/agents/examples/__init__.py +0 -3
  112. django_cfg/apps/agents/examples/simple_example.py +0 -161
  113. django_cfg/apps/knowbase/examples/__init__.py +0 -3
  114. django_cfg/apps/knowbase/examples/external_data_usage.py +0 -191
  115. django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +0 -199
  116. django_cfg/apps/payments/services/base.py +0 -68
  117. django_cfg/apps/payments/services/nowpayments.py +0 -78
  118. django_cfg/apps/payments/services/providers.py +0 -77
  119. django_cfg/apps/payments/services/redis_service.py +0 -215
  120. django_cfg/modules/django_currency/cache.py +0 -430
  121. django_cfg/modules/django_currency/converter.py +0 -324
  122. django_cfg/modules/django_currency/service.py +0 -277
  123. {django_cfg-1.2.22.dist-info → django_cfg-1.2.25.dist-info}/WHEEL +0 -0
  124. {django_cfg-1.2.22.dist-info → django_cfg-1.2.25.dist-info}/entry_points.txt +0 -0
  125. {django_cfg-1.2.22.dist-info → django_cfg-1.2.25.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,293 @@
1
+ """
2
+ NowPayments provider implementation.
3
+
4
+ Enhanced crypto payment provider with minimal typing.
5
+ """
6
+
7
+ import logging
8
+ import requests
9
+ import hashlib
10
+ import hmac
11
+ from typing import Optional, List
12
+ from decimal import Decimal
13
+ from pydantic import BaseModel, Field
14
+
15
+ from .base import PaymentProvider
16
+ from ..internal_types import ProviderResponse, WebhookData
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class NowPaymentsConfig(BaseModel):
22
+ """NowPayments provider configuration."""
23
+ api_key: str = Field(..., description="NowPayments API key")
24
+ sandbox: bool = Field(default=False, description="Use sandbox mode")
25
+ ipn_secret: Optional[str] = Field(default=None, description="IPN secret for webhook validation")
26
+ callback_url: Optional[str] = Field(default=None, description="Webhook callback URL")
27
+ success_url: Optional[str] = Field(default=None, description="Payment success redirect URL")
28
+ cancel_url: Optional[str] = Field(default=None, description="Payment cancel redirect URL")
29
+ enabled: bool = Field(default=True, description="Provider enabled")
30
+
31
+
32
+ class NowPaymentsProvider(PaymentProvider):
33
+ """NowPayments cryptocurrency payment provider."""
34
+
35
+ def __init__(self, config: NowPaymentsConfig):
36
+ """Initialize NowPayments provider."""
37
+ super().__init__(config.dict())
38
+ self.config = config
39
+ self.api_key = config.api_key
40
+ self.sandbox = config.sandbox
41
+ self.ipn_secret = config.ipn_secret or ''
42
+ self.base_url = self._get_base_url()
43
+
44
+ # Configurable URLs
45
+ self.callback_url = config.callback_url
46
+ self.success_url = config.success_url
47
+ self.cancel_url = config.cancel_url
48
+
49
+ self.headers = {
50
+ 'x-api-key': self.api_key,
51
+ 'Content-Type': 'application/json'
52
+ }
53
+
54
+ def _get_base_url(self) -> str:
55
+ """Get base URL based on sandbox mode."""
56
+ if self.sandbox:
57
+ return 'https://api-sandbox.nowpayments.io/v1'
58
+ return 'https://api.nowpayments.io/v1'
59
+
60
+ def _make_request(self, method: str, endpoint: str, data: Optional[dict] = None) -> Optional[dict]:
61
+ """Make HTTP request to NowPayments API with error handling."""
62
+ try:
63
+ url = f"{self.base_url}/{endpoint}"
64
+
65
+ response = requests.request(
66
+ method=method,
67
+ url=url,
68
+ headers=self.headers,
69
+ json=data,
70
+ timeout=30
71
+ )
72
+
73
+ response.raise_for_status()
74
+ return response.json()
75
+
76
+ except requests.exceptions.RequestException as e:
77
+ logger.error(f"NowPayments API request failed: {e}")
78
+ return None
79
+ except Exception as e:
80
+ logger.error(f"Unexpected error in NowPayments request: {e}")
81
+ return None
82
+
83
+ def create_payment(self, payment_data: dict) -> ProviderResponse:
84
+ """Create payment via NowPayments API."""
85
+ try:
86
+ amount = Decimal(str(payment_data['amount']))
87
+ currency = payment_data['currency']
88
+ order_id = payment_data.get('order_id', f'payment_{int(amount * 100)}_{currency}')
89
+
90
+ payment_request = {
91
+ 'price_amount': float(amount),
92
+ 'price_currency': 'usd', # Base currency
93
+ 'pay_currency': currency,
94
+ 'order_id': order_id,
95
+ 'order_description': payment_data.get('description', f'Payment {order_id}'),
96
+ }
97
+
98
+ # Add optional URLs
99
+ if self.success_url:
100
+ payment_request['success_url'] = self.success_url
101
+ if self.cancel_url:
102
+ payment_request['cancel_url'] = self.cancel_url
103
+ if self.callback_url:
104
+ payment_request['ipn_callback_url'] = self.callback_url
105
+
106
+ response = self._make_request('POST', 'payment', payment_request)
107
+
108
+ if response:
109
+ return ProviderResponse(
110
+ success=True,
111
+ provider_payment_id=response.get('payment_id'),
112
+ payment_url=response.get('invoice_url'),
113
+ pay_address=response.get('pay_address'),
114
+ amount=Decimal(str(response.get('pay_amount', 0))),
115
+ currency=response.get('pay_currency'),
116
+ status='pending'
117
+ )
118
+ else:
119
+ return ProviderResponse(
120
+ success=False,
121
+ error_message='Failed to create payment'
122
+ )
123
+
124
+ except Exception as e:
125
+ logger.error(f"NowPayments create_payment error: {e}")
126
+ return ProviderResponse(
127
+ success=False,
128
+ error_message=str(e)
129
+ )
130
+
131
+ def check_payment_status(self, payment_id: str) -> ProviderResponse:
132
+ """Check payment status via NowPayments API."""
133
+ try:
134
+ response = self._make_request('GET', f'payment/{payment_id}')
135
+
136
+ if response:
137
+ # Map NowPayments status to universal status
138
+ status_mapping = {
139
+ 'waiting': 'pending',
140
+ 'confirming': 'processing',
141
+ 'confirmed': 'completed',
142
+ 'sending': 'processing',
143
+ 'partially_paid': 'pending',
144
+ 'finished': 'completed',
145
+ 'failed': 'failed',
146
+ 'refunded': 'refunded',
147
+ 'expired': 'expired'
148
+ }
149
+
150
+ provider_status = response.get('payment_status', 'unknown')
151
+ universal_status = status_mapping.get(provider_status, 'unknown')
152
+
153
+ return ProviderResponse(
154
+ success=True,
155
+ provider_payment_id=response.get('payment_id'),
156
+ status=universal_status,
157
+ pay_address=response.get('pay_address'),
158
+ amount=Decimal(str(response.get('pay_amount', 0))),
159
+ currency=response.get('pay_currency')
160
+ )
161
+ else:
162
+ return ProviderResponse(
163
+ success=False,
164
+ error_message='Payment not found'
165
+ )
166
+
167
+ except Exception as e:
168
+ logger.error(f"NowPayments check_payment_status error: {e}")
169
+ return ProviderResponse(
170
+ success=False,
171
+ error_message=str(e)
172
+ )
173
+
174
+ def process_webhook(self, payload: dict) -> WebhookData:
175
+ """Process NowPayments webhook."""
176
+ try:
177
+ # Map status
178
+ status_mapping = {
179
+ 'waiting': 'pending',
180
+ 'confirming': 'processing',
181
+ 'confirmed': 'completed',
182
+ 'sending': 'processing',
183
+ 'partially_paid': 'pending',
184
+ 'finished': 'completed',
185
+ 'failed': 'failed',
186
+ 'refunded': 'refunded',
187
+ 'expired': 'expired'
188
+ }
189
+
190
+ provider_status = payload.get('payment_status', 'unknown')
191
+ universal_status = status_mapping.get(provider_status, 'unknown')
192
+
193
+ return WebhookData(
194
+ provider_payment_id=str(payload.get('payment_id', '')),
195
+ status=universal_status,
196
+ pay_amount=Decimal(str(payload.get('pay_amount', 0))),
197
+ actually_paid=Decimal(str(payload.get('actually_paid', 0))),
198
+ order_id=payload.get('order_id'),
199
+ signature=payload.get('signature')
200
+ )
201
+
202
+ except Exception as e:
203
+ logger.error(f"NowPayments webhook processing error: {e}")
204
+ raise
205
+
206
+ def get_supported_currencies(self) -> List[str]:
207
+ """Get list of supported currencies."""
208
+ try:
209
+ response = self._make_request('GET', 'currencies')
210
+
211
+ if response and 'currencies' in response:
212
+ return response['currencies']
213
+ else:
214
+ # Fallback currencies
215
+ return ['BTC', 'ETH', 'LTC', 'BCH', 'XMR', 'TRX', 'BNB']
216
+
217
+ except Exception as e:
218
+ logger.error(f"Error getting supported currencies: {e}")
219
+ return ['BTC', 'ETH', 'LTC'] # Minimal fallback
220
+
221
+ def get_minimum_payment_amount(self, currency_from: str, currency_to: str = 'usd') -> Optional[Decimal]:
222
+ """Get minimum payment amount for currency pair."""
223
+ try:
224
+ response = self._make_request('GET', 'min-amount', {
225
+ 'currency_from': currency_from,
226
+ 'currency_to': currency_to
227
+ })
228
+
229
+ if response and 'min_amount' in response:
230
+ return Decimal(str(response['min_amount']))
231
+
232
+ return None
233
+
234
+ except Exception as e:
235
+ logger.error(f"Error getting minimum amount: {e}")
236
+ return None
237
+
238
+ def estimate_payment_amount(self, amount: Decimal, currency_code: str) -> Optional[dict]:
239
+ """Estimate payment amount in target currency."""
240
+ try:
241
+ response = self._make_request('GET', 'estimate', {
242
+ 'amount': float(amount),
243
+ 'currency_from': 'usd',
244
+ 'currency_to': currency_code
245
+ })
246
+
247
+ if response and 'estimated_amount' in response:
248
+ return {
249
+ 'estimated_amount': Decimal(str(response['estimated_amount'])),
250
+ 'currency_from': response.get('currency_from'),
251
+ 'currency_to': response.get('currency_to'),
252
+ 'fee_amount': Decimal(str(response.get('fee_amount', 0)))
253
+ }
254
+
255
+ return None
256
+
257
+ except Exception as e:
258
+ logger.error(f"Error estimating payment amount: {e}")
259
+ return None
260
+
261
+ def validate_webhook(self, payload: dict, headers: Optional[dict] = None) -> bool:
262
+ """Validate NowPayments webhook signature."""
263
+ try:
264
+ if not self.ipn_secret:
265
+ logger.warning("IPN secret not configured, skipping webhook validation")
266
+ return True
267
+
268
+ if not headers:
269
+ logger.warning("No headers provided for webhook validation")
270
+ return False
271
+
272
+ # Get signature from headers
273
+ signature = headers.get('x-nowpayments-sig')
274
+ if not signature:
275
+ logger.warning("No signature found in webhook headers")
276
+ return False
277
+
278
+ # TODO: Implement proper HMAC signature validation
279
+ # This requires the raw payload body for proper validation
280
+ logger.info("Webhook signature validation placeholder")
281
+ return True
282
+
283
+ except Exception as e:
284
+ logger.error(f"Webhook validation error: {e}")
285
+ return False
286
+
287
+ def check_api_status(self) -> bool:
288
+ """Check if NowPayments API is available."""
289
+ try:
290
+ response = self._make_request('GET', 'status')
291
+ return response is not None and response.get('message') == 'OK'
292
+ except:
293
+ return False
@@ -0,0 +1,103 @@
1
+ """
2
+ Provider registry for managing payment providers.
3
+
4
+ Central registry with lazy loading and typed configuration.
5
+ """
6
+
7
+ import logging
8
+ from typing import Optional, List
9
+
10
+ from .base import PaymentProvider
11
+ from .nowpayments import NowPaymentsProvider, NowPaymentsConfig
12
+ from .cryptapi import CryptAPIProvider, CryptAPIConfig
13
+ from .cryptomus import CryptomusProvider, CryptomusConfig
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class ProviderRegistry:
19
+ """Central registry for payment providers with typed configs."""
20
+
21
+ def __init__(self):
22
+ """Initialize registry with lazy loading."""
23
+ self._providers: dict[str, PaymentProvider] = {}
24
+ self._provider_configs: dict[str, dict] = {}
25
+ self._load_configurations()
26
+
27
+ def _load_configurations(self) -> None:
28
+ """Load provider configurations."""
29
+ try:
30
+ from ...utils.config_utils import get_payments_config
31
+ config = get_payments_config()
32
+
33
+ self._provider_configs = {}
34
+ for provider_name, provider_config in config.providers.items():
35
+ if provider_config.enabled:
36
+ self._provider_configs[provider_name] = provider_config.get_config_dict()
37
+
38
+ except Exception as e:
39
+ logger.warning(f"Failed to load provider configurations: {e}")
40
+ self._provider_configs = {}
41
+
42
+ def _create_provider(self, name: str, config_dict: dict) -> Optional[PaymentProvider]:
43
+ """Create provider instance from configuration with typed config."""
44
+ try:
45
+ if name == 'nowpayments':
46
+ config = NowPaymentsConfig(**config_dict)
47
+ return NowPaymentsProvider(config)
48
+ elif name == 'cryptapi':
49
+ config = CryptAPIConfig(**config_dict)
50
+ return CryptAPIProvider(config)
51
+ elif name == 'cryptomus':
52
+ config = CryptomusConfig(**config_dict)
53
+ return CryptomusProvider(config)
54
+ elif name == 'stripe':
55
+ # TODO: Implement StripeProvider with StripeConfig
56
+ return None
57
+ else:
58
+ logger.warning(f"Unknown provider type: {name}")
59
+ return None
60
+
61
+ except Exception as e:
62
+ logger.error(f"Failed to create provider {name}: {e}")
63
+ return None
64
+
65
+ def register_provider(self, name: str, provider: PaymentProvider) -> None:
66
+ """Register a payment provider instance."""
67
+ self._providers[name] = provider
68
+
69
+ def get_provider(self, name: str) -> Optional[PaymentProvider]:
70
+ """Get provider by name with lazy loading."""
71
+ # Check if already loaded
72
+ if name in self._providers:
73
+ return self._providers[name]
74
+
75
+ # Try to load from configuration
76
+ if name in self._provider_configs:
77
+ provider = self._create_provider(name, self._provider_configs[name])
78
+ if provider:
79
+ self._providers[name] = provider
80
+ return provider
81
+
82
+ return None
83
+
84
+ def list_providers(self) -> List[str]:
85
+ """Get list of available providers."""
86
+ available = set(self._providers.keys())
87
+ available.update(self._provider_configs.keys())
88
+ return list(available)
89
+
90
+ def get_active_providers(self) -> List[str]:
91
+ """Get list of active providers."""
92
+ active = []
93
+ for name in self.list_providers():
94
+ provider = self.get_provider(name)
95
+ if provider and provider.is_enabled():
96
+ active.append(name)
97
+ return active
98
+
99
+ def reload_providers(self) -> None:
100
+ """Reload all providers from configuration."""
101
+ logger.info("Reloading providers from configuration")
102
+ self._providers.clear()
103
+ self._load_configurations()
@@ -0,0 +1,34 @@
1
+ """
2
+ Security services for payment system.
3
+ Foundation layer security components.
4
+ """
5
+
6
+ from .webhook_validator import webhook_validator, WebhookValidator
7
+ from .error_handler import (
8
+ error_handler,
9
+ CentralizedErrorHandler,
10
+ PaymentError,
11
+ SecurityError,
12
+ ProviderError,
13
+ ValidationError,
14
+ ErrorSeverity,
15
+ ErrorCategory,
16
+ error_context
17
+ )
18
+ from .payment_notifications import payment_notifications, PaymentNotifications
19
+
20
+ __all__ = [
21
+ 'webhook_validator',
22
+ 'WebhookValidator',
23
+ 'error_handler',
24
+ 'CentralizedErrorHandler',
25
+ 'PaymentError',
26
+ 'SecurityError',
27
+ 'ProviderError',
28
+ 'ValidationError',
29
+ 'ErrorSeverity',
30
+ 'ErrorCategory',
31
+ 'error_context',
32
+ 'payment_notifications',
33
+ 'PaymentNotifications'
34
+ ]