django-cfg 1.2.31__py3-none-any.whl → 1.3.1__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.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/api/health/views.py +4 -2
- django_cfg/apps/knowbase/config/settings.py +16 -15
- django_cfg/apps/payments/README.md +326 -0
- django_cfg/apps/payments/admin/__init__.py +20 -10
- django_cfg/apps/payments/admin/api_keys_admin.py +521 -237
- django_cfg/apps/payments/admin/balance_admin.py +592 -297
- django_cfg/apps/payments/admin/currencies_admin.py +526 -222
- django_cfg/apps/payments/admin/filters.py +306 -199
- django_cfg/apps/payments/admin/payments_admin.py +465 -70
- django_cfg/apps/payments/admin/subscriptions_admin.py +578 -128
- django_cfg/apps/payments/admin_interface/__init__.py +18 -0
- django_cfg/apps/payments/admin_interface/templates/payments/base.html +162 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +38 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/loading_spinner.html +16 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/notification.html +27 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_card.html +86 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +39 -0
- django_cfg/apps/payments/admin_interface/templates/payments/currency_converter.html +382 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +300 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +303 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +382 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_status.html +500 -0
- django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +594 -0
- django_cfg/apps/payments/admin_interface/views/__init__.py +23 -0
- django_cfg/apps/payments/admin_interface/views/payment_views.py +259 -0
- django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +37 -0
- django_cfg/apps/payments/apps.py +34 -9
- django_cfg/apps/payments/config/__init__.py +28 -51
- django_cfg/apps/payments/config/constance/__init__.py +22 -0
- django_cfg/apps/payments/config/constance/config_service.py +123 -0
- django_cfg/apps/payments/config/constance/fields.py +69 -0
- django_cfg/apps/payments/config/constance/settings.py +160 -0
- django_cfg/apps/payments/config/django_cfg_integration.py +202 -0
- django_cfg/apps/payments/config/helpers.py +130 -0
- django_cfg/apps/payments/management/__init__.py +1 -3
- django_cfg/apps/payments/management/commands/__init__.py +1 -3
- django_cfg/apps/payments/management/commands/manage_currencies.py +303 -151
- django_cfg/apps/payments/management/commands/manage_providers.py +333 -160
- django_cfg/apps/payments/middleware/__init__.py +3 -1
- django_cfg/apps/payments/middleware/api_access.py +329 -222
- django_cfg/apps/payments/middleware/rate_limiting.py +342 -152
- django_cfg/apps/payments/middleware/usage_tracking.py +249 -240
- django_cfg/apps/payments/migrations/0001_initial.py +708 -536
- django_cfg/apps/payments/models/__init__.py +13 -18
- django_cfg/apps/payments/models/api_keys.py +121 -43
- django_cfg/apps/payments/models/balance.py +150 -115
- django_cfg/apps/payments/models/base.py +68 -15
- django_cfg/apps/payments/models/currencies.py +172 -148
- django_cfg/apps/payments/models/managers/__init__.py +44 -0
- django_cfg/apps/payments/models/managers/api_key_managers.py +329 -0
- django_cfg/apps/payments/models/managers/balance_managers.py +599 -0
- django_cfg/apps/payments/models/managers/currency_managers.py +385 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +511 -0
- django_cfg/apps/payments/models/managers/subscription_managers.py +641 -0
- django_cfg/apps/payments/models/payments.py +235 -285
- django_cfg/apps/payments/models/subscriptions.py +257 -177
- django_cfg/apps/payments/models/tariffs.py +147 -40
- django_cfg/apps/payments/services/__init__.py +209 -56
- django_cfg/apps/payments/services/cache/__init__.py +6 -6
- django_cfg/apps/payments/services/cache/{simple_cache.py → cache_service.py} +112 -12
- django_cfg/apps/payments/services/core/__init__.py +10 -6
- django_cfg/apps/payments/services/core/balance_service.py +435 -360
- django_cfg/apps/payments/services/core/base.py +166 -0
- django_cfg/apps/payments/services/core/currency_service.py +478 -0
- django_cfg/apps/payments/services/core/payment_service.py +346 -467
- django_cfg/apps/payments/services/core/subscription_service.py +425 -481
- django_cfg/apps/payments/services/core/webhook_service.py +410 -0
- django_cfg/apps/payments/services/integrations/__init__.py +29 -0
- django_cfg/apps/payments/services/integrations/ngrok_service.py +47 -0
- django_cfg/apps/payments/services/integrations/providers_config.py +107 -0
- django_cfg/apps/payments/services/providers/__init__.py +9 -14
- django_cfg/apps/payments/services/providers/base.py +234 -174
- django_cfg/apps/payments/services/providers/nowpayments.py +478 -0
- django_cfg/apps/payments/services/providers/registry.py +367 -301
- django_cfg/apps/payments/services/types/__init__.py +78 -0
- django_cfg/apps/payments/services/types/data.py +177 -0
- django_cfg/apps/payments/services/types/requests.py +150 -0
- django_cfg/apps/payments/services/types/responses.py +156 -0
- django_cfg/apps/payments/services/types/webhooks.py +232 -0
- django_cfg/apps/payments/signals/__init__.py +33 -8
- django_cfg/apps/payments/signals/api_key_signals.py +210 -129
- django_cfg/apps/payments/signals/balance_signals.py +174 -0
- django_cfg/apps/payments/signals/payment_signals.py +128 -103
- django_cfg/apps/payments/signals/subscription_signals.py +194 -142
- django_cfg/apps/payments/static/payments/css/components.css +380 -0
- django_cfg/apps/payments/static/payments/css/dashboard.css +188 -0
- django_cfg/apps/payments/static/payments/js/components.js +545 -0
- django_cfg/apps/payments/static/payments/js/utils.js +412 -0
- django_cfg/apps/payments/templatetags/__init__.py +1 -1
- django_cfg/apps/payments/templatetags/payment_tags.py +466 -0
- django_cfg/apps/payments/urls.py +45 -48
- django_cfg/apps/payments/urls_admin.py +33 -42
- django_cfg/apps/payments/views/api/__init__.py +101 -0
- django_cfg/apps/payments/views/api/api_keys.py +387 -0
- django_cfg/apps/payments/views/api/balances.py +381 -0
- django_cfg/apps/payments/views/api/base.py +298 -0
- django_cfg/apps/payments/views/api/currencies.py +402 -0
- django_cfg/apps/payments/views/api/payments.py +415 -0
- django_cfg/apps/payments/views/api/subscriptions.py +475 -0
- django_cfg/apps/payments/views/api/webhooks.py +476 -0
- django_cfg/apps/payments/views/serializers/__init__.py +99 -0
- django_cfg/apps/payments/views/serializers/api_keys.py +424 -0
- django_cfg/apps/payments/views/serializers/balances.py +300 -0
- django_cfg/apps/payments/views/serializers/currencies.py +335 -0
- django_cfg/apps/payments/views/serializers/payments.py +387 -0
- django_cfg/apps/payments/views/serializers/subscriptions.py +429 -0
- django_cfg/apps/payments/views/serializers/webhooks.py +137 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +40 -4
- django_cfg/core/generation.py +25 -4
- django_cfg/core/integration/README.md +363 -0
- django_cfg/core/integration/__init__.py +47 -0
- django_cfg/core/integration/commands_collector.py +239 -0
- django_cfg/core/integration/display/__init__.py +15 -0
- django_cfg/core/integration/display/base.py +157 -0
- django_cfg/core/integration/display/ngrok.py +164 -0
- django_cfg/core/integration/display/startup.py +815 -0
- django_cfg/core/integration/url_integration.py +123 -0
- django_cfg/core/integration/version_checker.py +160 -0
- django_cfg/management/commands/auto_generate.py +4 -0
- django_cfg/management/commands/check_settings.py +6 -0
- django_cfg/management/commands/clear_constance.py +5 -2
- django_cfg/management/commands/create_token.py +6 -0
- django_cfg/management/commands/list_urls.py +6 -0
- django_cfg/management/commands/migrate_all.py +6 -0
- django_cfg/management/commands/migrator.py +3 -0
- django_cfg/management/commands/rundramatiq.py +6 -0
- django_cfg/management/commands/runserver_ngrok.py +51 -29
- django_cfg/management/commands/script.py +6 -0
- django_cfg/management/commands/show_config.py +12 -2
- django_cfg/management/commands/show_urls.py +4 -0
- django_cfg/management/commands/superuser.py +6 -0
- django_cfg/management/commands/task_clear.py +4 -1
- django_cfg/management/commands/task_status.py +3 -1
- django_cfg/management/commands/test_email.py +3 -0
- django_cfg/management/commands/test_telegram.py +6 -0
- django_cfg/management/commands/test_twilio.py +6 -0
- django_cfg/management/commands/tree.py +6 -0
- django_cfg/management/commands/validate_config.py +155 -149
- django_cfg/models/constance.py +31 -11
- django_cfg/models/payments.py +175 -492
- django_cfg/modules/django_logger.py +160 -146
- django_cfg/modules/django_unfold/dashboard.py +64 -16
- django_cfg/registry/core.py +1 -0
- django_cfg/template_archive/django_sample.zip +0 -0
- django_cfg/utils/smart_defaults.py +222 -571
- django_cfg/utils/toolkit.py +51 -11
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/METADATA +4 -1
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/RECORD +153 -185
- django_cfg/apps/payments/__init__.py +0 -8
- django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
- django_cfg/apps/payments/config/module.py +0 -70
- django_cfg/apps/payments/config/providers.py +0 -105
- django_cfg/apps/payments/config/settings.py +0 -96
- django_cfg/apps/payments/config/utils.py +0 -52
- django_cfg/apps/payments/decorators.py +0 -291
- django_cfg/apps/payments/management/commands/README.md +0 -146
- django_cfg/apps/payments/management/commands/currency_stats.py +0 -304
- django_cfg/apps/payments/managers/__init__.py +0 -23
- django_cfg/apps/payments/managers/api_key_manager.py +0 -35
- django_cfg/apps/payments/managers/balance_manager.py +0 -361
- django_cfg/apps/payments/managers/currency_manager.py +0 -306
- django_cfg/apps/payments/managers/payment_manager.py +0 -192
- django_cfg/apps/payments/managers/subscription_manager.py +0 -37
- django_cfg/apps/payments/managers/tariff_manager.py +0 -29
- django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +0 -241
- django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +0 -30
- django_cfg/apps/payments/models/events.py +0 -73
- django_cfg/apps/payments/serializers/__init__.py +0 -57
- django_cfg/apps/payments/serializers/api_keys.py +0 -51
- django_cfg/apps/payments/serializers/balance.py +0 -59
- django_cfg/apps/payments/serializers/currencies.py +0 -63
- django_cfg/apps/payments/serializers/payments.py +0 -62
- django_cfg/apps/payments/serializers/subscriptions.py +0 -71
- django_cfg/apps/payments/serializers/tariffs.py +0 -56
- django_cfg/apps/payments/services/billing/__init__.py +0 -8
- django_cfg/apps/payments/services/cache/base.py +0 -30
- django_cfg/apps/payments/services/core/fallback_service.py +0 -432
- django_cfg/apps/payments/services/internal_types.py +0 -461
- django_cfg/apps/payments/services/middleware/__init__.py +0 -8
- django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
- django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -76
- django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
- django_cfg/apps/payments/services/providers/cryptapi/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/cryptapi/config.py +0 -8
- django_cfg/apps/payments/services/providers/cryptapi/models.py +0 -192
- django_cfg/apps/payments/services/providers/cryptapi/provider.py +0 -439
- django_cfg/apps/payments/services/providers/cryptomus/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/cryptomus/models.py +0 -176
- django_cfg/apps/payments/services/providers/cryptomus/provider.py +0 -429
- django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +0 -564
- django_cfg/apps/payments/services/providers/models/__init__.py +0 -34
- django_cfg/apps/payments/services/providers/models/currencies.py +0 -190
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/nowpayments/models.py +0 -196
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +0 -380
- django_cfg/apps/payments/services/providers/stripe/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/stripe/models.py +0 -184
- django_cfg/apps/payments/services/providers/stripe/provider.py +0 -109
- django_cfg/apps/payments/services/security/__init__.py +0 -34
- django_cfg/apps/payments/services/security/error_handler.py +0 -635
- django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
- django_cfg/apps/payments/services/security/webhook_validator.py +0 -474
- django_cfg/apps/payments/static/payments/css/payments.css +0 -340
- django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
- django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
- django_cfg/apps/payments/static/payments/js/theme.js +0 -86
- django_cfg/apps/payments/tasks/__init__.py +0 -12
- django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +0 -50
- django_cfg/apps/payments/templates/payments/base.html +0 -182
- django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
- django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
- django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -43
- django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
- django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -34
- django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -148
- django_cfg/apps/payments/templates/payments/dashboard.html +0 -258
- django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +0 -35
- django_cfg/apps/payments/templates/payments/payment_create.html +0 -579
- django_cfg/apps/payments/templates/payments/payment_detail.html +0 -373
- django_cfg/apps/payments/templates/payments/payment_list.html +0 -354
- django_cfg/apps/payments/templates/payments/stats.html +0 -261
- django_cfg/apps/payments/templates/payments/test.html +0 -213
- django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
- django_cfg/apps/payments/utils/__init__.py +0 -43
- django_cfg/apps/payments/utils/billing_utils.py +0 -342
- django_cfg/apps/payments/utils/config_utils.py +0 -239
- django_cfg/apps/payments/utils/middleware_utils.py +0 -228
- django_cfg/apps/payments/utils/validation_utils.py +0 -94
- django_cfg/apps/payments/views/__init__.py +0 -63
- django_cfg/apps/payments/views/api_key_views.py +0 -164
- django_cfg/apps/payments/views/balance_views.py +0 -75
- django_cfg/apps/payments/views/currency_views.py +0 -122
- django_cfg/apps/payments/views/payment_views.py +0 -149
- django_cfg/apps/payments/views/subscription_views.py +0 -135
- django_cfg/apps/payments/views/tariff_views.py +0 -131
- django_cfg/apps/payments/views/templates/__init__.py +0 -25
- django_cfg/apps/payments/views/templates/ajax.py +0 -451
- django_cfg/apps/payments/views/templates/base.py +0 -212
- django_cfg/apps/payments/views/templates/dashboard.py +0 -60
- django_cfg/apps/payments/views/templates/payment_detail.py +0 -102
- django_cfg/apps/payments/views/templates/payment_management.py +0 -158
- django_cfg/apps/payments/views/templates/qr_code.py +0 -174
- django_cfg/apps/payments/views/templates/stats.py +0 -244
- django_cfg/apps/payments/views/templates/utils.py +0 -181
- django_cfg/apps/payments/views/webhook_views.py +0 -266
- django_cfg/apps/payments/viewsets.py +0 -66
- django_cfg/core/integration.py +0 -160
- django_cfg/template_archive/.gitignore +0 -1
- django_cfg/template_archive/__init__.py +0 -0
- django_cfg/urls.py +0 -33
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,238 +1,298 @@
|
|
1
1
|
"""
|
2
|
-
Base
|
2
|
+
Base provider class for the Universal Payment System v2.0.
|
3
3
|
|
4
|
-
Abstract base class for all payment providers.
|
4
|
+
Abstract base class for all payment providers with unified interface.
|
5
5
|
"""
|
6
6
|
|
7
7
|
from abc import ABC, abstractmethod
|
8
|
-
from typing import Optional, List
|
9
|
-
from django.db.models import QuerySet
|
8
|
+
from typing import Dict, Any, Optional, List
|
10
9
|
from decimal import Decimal
|
10
|
+
from pydantic import BaseModel, Field
|
11
|
+
from django_cfg.modules.django_logger import get_logger
|
12
|
+
from ..types import ProviderResponse, ServiceOperationResult
|
11
13
|
|
12
|
-
from django.db import models, transaction
|
13
|
-
from cachetools import TTLCache
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
class ProviderConfig(BaseModel):
|
16
|
+
"""
|
17
|
+
Base provider configuration.
|
18
|
+
|
19
|
+
Common configuration fields for all payment providers.
|
20
|
+
"""
|
21
|
+
|
22
|
+
provider_name: str = Field(description="Provider name")
|
23
|
+
api_key: str = Field(description="Provider API key")
|
24
|
+
api_url: str = Field(description="Provider API URL")
|
25
|
+
sandbox: bool = Field(default=False, description="Sandbox mode")
|
26
|
+
timeout: int = Field(default=30, description="Request timeout in seconds")
|
27
|
+
retry_attempts: int = Field(default=3, description="Number of retry attempts")
|
28
|
+
retry_delay: int = Field(default=5, description="Delay between retries in seconds")
|
29
|
+
min_amount_usd: float = Field(default=1.0, description="Minimum amount in USD")
|
30
|
+
max_amount_usd: float = Field(default=50000.0, description="Maximum amount in USD")
|
31
|
+
supported_currencies: List[str] = Field(default_factory=list, description="Supported currencies")
|
32
|
+
webhook_secret: Optional[str] = Field(None, description="Webhook secret for validation")
|
18
33
|
|
19
34
|
|
20
|
-
|
35
|
+
class PaymentRequest(BaseModel):
|
36
|
+
"""
|
37
|
+
Universal payment request for providers.
|
38
|
+
|
39
|
+
Standardized payment creation request across all providers.
|
40
|
+
"""
|
41
|
+
|
42
|
+
amount_usd: float = Field(gt=0, description="Amount in USD")
|
43
|
+
currency_code: str = Field(description="Cryptocurrency code")
|
44
|
+
order_id: str = Field(description="Internal order/payment ID")
|
45
|
+
callback_url: Optional[str] = Field(None, description="Success callback URL")
|
46
|
+
cancel_url: Optional[str] = Field(None, description="Cancel URL")
|
47
|
+
description: Optional[str] = Field(None, description="Payment description")
|
48
|
+
customer_email: Optional[str] = Field(None, description="Customer email")
|
49
|
+
metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
|
50
|
+
|
21
51
|
|
22
|
-
class
|
23
|
-
"""
|
52
|
+
class BaseProvider(ABC):
|
53
|
+
"""
|
54
|
+
Abstract base class for payment providers.
|
24
55
|
|
25
|
-
|
26
|
-
|
56
|
+
Defines the unified interface that all providers must implement.
|
57
|
+
"""
|
27
58
|
|
28
|
-
def __init__(self, config):
|
29
|
-
"""
|
30
|
-
|
31
|
-
self.name = self.__class__.__name__.lower().replace('provider', '')
|
32
|
-
self.logger = get_logger(f"payment.{self.name}")
|
59
|
+
def __init__(self, config: ProviderConfig):
|
60
|
+
"""
|
61
|
+
Initialize provider with configuration.
|
33
62
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
63
|
+
Args:
|
64
|
+
config: Provider configuration
|
65
|
+
"""
|
66
|
+
self.config = config
|
67
|
+
self.logger = get_logger(f"providers.{config.provider_name}")
|
68
|
+
self._session = None
|
69
|
+
|
70
|
+
@property
|
71
|
+
def name(self) -> str:
|
72
|
+
"""Get provider name."""
|
73
|
+
return self.config.provider_name
|
74
|
+
|
75
|
+
@property
|
76
|
+
def is_sandbox(self) -> bool:
|
77
|
+
"""Check if provider is in sandbox mode."""
|
78
|
+
return self.config.sandbox
|
41
79
|
|
42
80
|
@abstractmethod
|
43
|
-
def create_payment(self,
|
81
|
+
def create_payment(self, request: PaymentRequest) -> ProviderResponse:
|
44
82
|
"""
|
45
|
-
Create
|
83
|
+
Create payment with provider.
|
46
84
|
|
47
85
|
Args:
|
48
|
-
|
49
|
-
currency: Payment currency
|
50
|
-
**kwargs: Additional parameters (order_id, description, etc.)
|
86
|
+
request: Payment creation request
|
51
87
|
|
52
88
|
Returns:
|
53
|
-
|
89
|
+
ProviderResponse: Provider response with payment details
|
54
90
|
"""
|
55
91
|
pass
|
56
92
|
|
57
93
|
@abstractmethod
|
58
|
-
def
|
94
|
+
def get_payment_status(self, provider_payment_id: str) -> ProviderResponse:
|
59
95
|
"""
|
60
|
-
|
96
|
+
Get payment status from provider.
|
61
97
|
|
62
98
|
Args:
|
63
|
-
|
99
|
+
provider_payment_id: Provider's payment ID
|
64
100
|
|
65
101
|
Returns:
|
66
|
-
|
102
|
+
ProviderResponse: Current payment status
|
67
103
|
"""
|
68
104
|
pass
|
69
105
|
|
70
106
|
@abstractmethod
|
71
|
-
def
|
107
|
+
def get_supported_currencies(self) -> ServiceOperationResult:
|
72
108
|
"""
|
73
|
-
|
109
|
+
Get list of supported currencies from provider.
|
74
110
|
|
75
|
-
Args:
|
76
|
-
payload: Webhook data from provider
|
77
|
-
|
78
111
|
Returns:
|
79
|
-
|
112
|
+
ServiceOperationResult: List of supported currencies
|
80
113
|
"""
|
81
114
|
pass
|
82
115
|
|
83
|
-
@abstractmethod
|
84
|
-
def
|
116
|
+
@abstractmethod
|
117
|
+
def validate_webhook(self, payload: Dict[str, Any], signature: str = None) -> ServiceOperationResult:
|
85
118
|
"""
|
86
|
-
|
87
|
-
|
88
|
-
This method should:
|
89
|
-
1. Fetch data from provider API
|
90
|
-
2. Parse provider codes into base_currency + network
|
91
|
-
3. Return universal format
|
119
|
+
Validate webhook from provider.
|
92
120
|
|
121
|
+
Args:
|
122
|
+
payload: Webhook payload
|
123
|
+
signature: Webhook signature (if any)
|
124
|
+
|
93
125
|
Returns:
|
94
|
-
|
126
|
+
ServiceOperationResult: Validation result
|
95
127
|
"""
|
96
128
|
pass
|
97
129
|
|
98
|
-
|
99
|
-
|
100
|
-
def validate_webhook(self, payload: dict, headers: Optional[dict] = None) -> bool:
|
130
|
+
def get_exchange_rate(self, from_currency: str, to_currency: str) -> ServiceOperationResult:
|
101
131
|
"""
|
102
|
-
|
132
|
+
Get exchange rate from provider (optional).
|
103
133
|
|
104
134
|
Args:
|
105
|
-
|
106
|
-
|
135
|
+
from_currency: Source currency
|
136
|
+
to_currency: Target currency
|
107
137
|
|
108
138
|
Returns:
|
109
|
-
|
139
|
+
ServiceOperationResult: Exchange rate or not supported
|
110
140
|
"""
|
111
|
-
|
112
|
-
|
113
|
-
|
141
|
+
return ServiceOperationResult(
|
142
|
+
success=False,
|
143
|
+
message=f"Exchange rates not supported by {self.name}",
|
144
|
+
error_code="not_supported"
|
145
|
+
)
|
114
146
|
|
115
|
-
def
|
147
|
+
def health_check(self) -> ServiceOperationResult:
|
116
148
|
"""
|
117
|
-
|
149
|
+
Perform provider health check.
|
118
150
|
|
119
151
|
Returns:
|
120
|
-
|
152
|
+
ServiceOperationResult: Health check result
|
121
153
|
"""
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
154
|
+
try:
|
155
|
+
# Basic connectivity test - can be overridden by providers
|
156
|
+
result = self.get_supported_currencies()
|
157
|
+
|
158
|
+
if result.success:
|
159
|
+
return ServiceOperationResult(
|
160
|
+
success=True,
|
161
|
+
message=f"{self.name} provider is healthy",
|
162
|
+
data={
|
163
|
+
'provider': self.name,
|
164
|
+
'sandbox': self.is_sandbox,
|
165
|
+
'api_url': self.config.api_url,
|
166
|
+
'supported_currencies_count': len(result.data.get('currencies', []))
|
167
|
+
}
|
168
|
+
)
|
169
|
+
else:
|
170
|
+
return ServiceOperationResult(
|
171
|
+
success=False,
|
172
|
+
message=f"{self.name} provider health check failed",
|
173
|
+
error_code="health_check_failed",
|
174
|
+
data={'provider': self.name, 'error': result.message}
|
175
|
+
)
|
176
|
+
|
177
|
+
except Exception as e:
|
178
|
+
self.logger.error(f"Health check failed for {self.name}: {e}")
|
179
|
+
return ServiceOperationResult(
|
180
|
+
success=False,
|
181
|
+
message=f"{self.name} provider health check error: {e}",
|
182
|
+
error_code="health_check_error",
|
183
|
+
data={'provider': self.name}
|
184
|
+
)
|
128
185
|
|
129
|
-
def
|
186
|
+
def _make_request(
|
187
|
+
self,
|
188
|
+
method: str,
|
189
|
+
endpoint: str,
|
190
|
+
data: Optional[Dict[str, Any]] = None,
|
191
|
+
headers: Optional[Dict[str, str]] = None
|
192
|
+
) -> Dict[str, Any]:
|
130
193
|
"""
|
131
|
-
|
132
|
-
|
194
|
+
Make HTTP request to provider API.
|
195
|
+
|
196
|
+
Args:
|
197
|
+
method: HTTP method
|
198
|
+
endpoint: API endpoint
|
199
|
+
data: Request data
|
200
|
+
headers: Request headers
|
201
|
+
|
202
|
+
Returns:
|
203
|
+
Dict[str, Any]: Response data
|
204
|
+
|
205
|
+
Raises:
|
206
|
+
Exception: If request fails
|
133
207
|
"""
|
134
|
-
|
208
|
+
import requests
|
209
|
+
from requests.adapters import HTTPAdapter
|
210
|
+
from urllib3.util.retry import Retry
|
135
211
|
|
136
|
-
#
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
'network': network,
|
186
|
-
'is_enabled': universal_currency.is_enabled,
|
187
|
-
'is_popular': universal_currency.is_popular,
|
188
|
-
'is_stable': universal_currency.is_stable,
|
189
|
-
'priority': universal_currency.priority,
|
190
|
-
'logo_url': universal_currency.logo_url,
|
191
|
-
'available_for_payment': universal_currency.available_for_payment,
|
192
|
-
'available_for_payout': universal_currency.available_for_payout,
|
193
|
-
'min_amount': universal_currency.min_amount,
|
194
|
-
'max_amount': universal_currency.max_amount,
|
195
|
-
'metadata': universal_currency.raw_data
|
196
|
-
}
|
197
|
-
)
|
198
|
-
|
199
|
-
if created:
|
200
|
-
result.provider_currencies_created += 1
|
201
|
-
logger.debug(f"Created provider currency: {universal_currency.provider_currency_code}")
|
202
|
-
else:
|
203
|
-
# Update existing record
|
204
|
-
provider_currency.is_enabled = universal_currency.is_enabled
|
205
|
-
provider_currency.is_popular = universal_currency.is_popular
|
206
|
-
provider_currency.is_stable = universal_currency.is_stable
|
207
|
-
provider_currency.priority = universal_currency.priority
|
208
|
-
provider_currency.logo_url = universal_currency.logo_url
|
209
|
-
provider_currency.save()
|
210
|
-
result.provider_currencies_updated += 1
|
211
|
-
|
212
|
-
except Exception as e:
|
213
|
-
error_msg = f"Error processing {universal_currency.provider_currency_code}: {str(e)}"
|
214
|
-
result.errors.append(error_msg)
|
215
|
-
logger.error(error_msg)
|
212
|
+
# Create session if not exists
|
213
|
+
if self._session is None:
|
214
|
+
self._session = requests.Session()
|
215
|
+
|
216
|
+
# Configure retries
|
217
|
+
retry_strategy = Retry(
|
218
|
+
total=self.config.retry_attempts,
|
219
|
+
backoff_factor=self.config.retry_delay,
|
220
|
+
status_forcelist=[429, 500, 502, 503, 504],
|
221
|
+
)
|
222
|
+
adapter = HTTPAdapter(max_retries=retry_strategy)
|
223
|
+
self._session.mount("http://", adapter)
|
224
|
+
self._session.mount("https://", adapter)
|
225
|
+
|
226
|
+
# Build URL
|
227
|
+
url = f"{self.config.api_url.rstrip('/')}/{endpoint.lstrip('/')}"
|
228
|
+
|
229
|
+
# Prepare headers
|
230
|
+
request_headers = {
|
231
|
+
'Content-Type': 'application/json',
|
232
|
+
'User-Agent': f'django-cfg-payments/2.0 ({self.name})',
|
233
|
+
}
|
234
|
+
if headers:
|
235
|
+
request_headers.update(headers)
|
236
|
+
|
237
|
+
# Log request
|
238
|
+
self.logger.debug(f"Making {method} request to {url}", extra={
|
239
|
+
'method': method,
|
240
|
+
'url': url,
|
241
|
+
'has_data': bool(data)
|
242
|
+
})
|
243
|
+
|
244
|
+
# Make request
|
245
|
+
response = self._session.request(
|
246
|
+
method=method,
|
247
|
+
url=url,
|
248
|
+
json=data if data else None,
|
249
|
+
headers=request_headers,
|
250
|
+
timeout=self.config.timeout
|
251
|
+
)
|
252
|
+
|
253
|
+
# Log response
|
254
|
+
self.logger.debug(f"Received response: {response.status_code}", extra={
|
255
|
+
'status_code': response.status_code,
|
256
|
+
'response_size': len(response.content)
|
257
|
+
})
|
258
|
+
|
259
|
+
# Handle response
|
260
|
+
response.raise_for_status()
|
216
261
|
|
217
|
-
logger.info(f"Sync completed: {result}")
|
218
|
-
return result
|
219
|
-
|
220
|
-
def get_provider_info(self) -> ProviderInfo:
|
221
|
-
"""Get provider information using parsed currencies."""
|
222
262
|
try:
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
263
|
+
return response.json()
|
264
|
+
except ValueError:
|
265
|
+
# Non-JSON response
|
266
|
+
return {'raw_response': response.text, 'status_code': response.status_code}
|
267
|
+
|
268
|
+
def _create_provider_response(
|
269
|
+
self,
|
270
|
+
success: bool,
|
271
|
+
raw_response: Dict[str, Any],
|
272
|
+
**kwargs
|
273
|
+
) -> ProviderResponse:
|
274
|
+
"""
|
275
|
+
Create standardized provider response.
|
276
|
+
|
277
|
+
Args:
|
278
|
+
success: Operation success
|
279
|
+
raw_response: Raw provider response
|
280
|
+
**kwargs: Additional response fields
|
281
|
+
|
282
|
+
Returns:
|
283
|
+
ProviderResponse: Standardized response
|
284
|
+
"""
|
285
|
+
return ProviderResponse(
|
286
|
+
provider=self.name,
|
287
|
+
success=success,
|
288
|
+
raw_response=raw_response,
|
289
|
+
**kwargs
|
238
290
|
)
|
291
|
+
|
292
|
+
def __str__(self) -> str:
|
293
|
+
"""String representation."""
|
294
|
+
return f"{self.name}Provider(sandbox={self.is_sandbox})"
|
295
|
+
|
296
|
+
def __repr__(self) -> str:
|
297
|
+
"""Detailed representation."""
|
298
|
+
return f"{self.__class__.__name__}(name='{self.name}', sandbox={self.is_sandbox}, api_url='{self.config.api_url}')"
|