django-cfg 1.2.29__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 -9
- 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 +600 -108
- django_cfg/apps/payments/admin/filters.py +306 -199
- django_cfg/apps/payments/admin/payments_admin.py +470 -64
- 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 +381 -0
- django_cfg/apps/payments/management/commands/manage_providers.py +408 -0
- 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 +343 -163
- django_cfg/apps/payments/middleware/usage_tracking.py +250 -238
- django_cfg/apps/payments/migrations/0001_initial.py +708 -536
- django_cfg/apps/payments/models/__init__.py +16 -20
- 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 +207 -67
- 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 -284
- 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 +344 -468
- django_cfg/apps/payments/services/core/subscription_service.py +425 -484
- 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 +232 -71
- django_cfg/apps/payments/services/providers/nowpayments.py +404 -219
- django_cfg/apps/payments/services/providers/registry.py +429 -80
- 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 +211 -130
- django_cfg/apps/payments/signals/balance_signals.py +174 -0
- django_cfg/apps/payments/signals/payment_signals.py +129 -98
- django_cfg/apps/payments/signals/subscription_signals.py +195 -143
- 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 +46 -47
- django_cfg/apps/payments/urls_admin.py +49 -0
- 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/apps/tasks/urls.py +0 -2
- django_cfg/apps/tasks/urls_admin.py +14 -0
- django_cfg/apps/urls.py +4 -4
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +75 -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 -498
- django_cfg/modules/django_currency/__init__.py +16 -11
- django_cfg/modules/django_currency/clients/__init__.py +4 -4
- django_cfg/modules/django_currency/clients/coinpaprika_client.py +289 -0
- django_cfg/modules/django_currency/clients/yahoo_client.py +157 -0
- django_cfg/modules/django_currency/core/__init__.py +1 -7
- django_cfg/modules/django_currency/core/converter.py +18 -23
- django_cfg/modules/django_currency/core/models.py +122 -11
- django_cfg/modules/django_currency/database/__init__.py +4 -4
- django_cfg/modules/django_currency/database/database_loader.py +190 -309
- django_cfg/modules/django_logger.py +160 -146
- django_cfg/modules/django_unfold/dashboard.py +65 -12
- django_cfg/registry/core.py +1 -0
- django_cfg/template_archive/django_sample.zip +0 -0
- django_cfg/templates/admin/components/action_grid.html +9 -9
- django_cfg/templates/admin/components/metric_card.html +5 -5
- django_cfg/templates/admin/components/status_badge.html +2 -2
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +152 -24
- django_cfg/templates/admin/snippets/components/quick_actions.html +3 -3
- django_cfg/templates/admin/snippets/components/system_health.html +1 -1
- django_cfg/templates/admin/snippets/tabs/overview_tab.html +49 -52
- django_cfg/utils/smart_defaults.py +222 -571
- django_cfg/utils/toolkit.py +51 -11
- {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/METADATA +5 -4
- {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/RECORD +172 -182
- 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 -178
- django_cfg/apps/payments/management/commands/currency_stats.py +0 -323
- django_cfg/apps/payments/management/commands/populate_currencies.py +0 -246
- django_cfg/apps/payments/management/commands/update_currencies.py +0 -336
- django_cfg/apps/payments/managers/__init__.py +0 -22
- 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 -83
- django_cfg/apps/payments/managers/payment_manager.py +0 -44
- django_cfg/apps/payments/managers/subscription_manager.py +0 -37
- django_cfg/apps/payments/managers/tariff_manager.py +0 -29
- django_cfg/apps/payments/models/events.py +0 -73
- django_cfg/apps/payments/serializers/__init__.py +0 -56
- 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 -55
- 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 -297
- 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 -222
- django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
- django_cfg/apps/payments/services/providers/cryptapi.py +0 -273
- django_cfg/apps/payments/services/providers/cryptomus.py +0 -311
- django_cfg/apps/payments/services/security/__init__.py +0 -34
- django_cfg/apps/payments/services/security/error_handler.py +0 -637
- django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
- django_cfg/apps/payments/services/security/webhook_validator.py +0 -475
- django_cfg/apps/payments/services/validators/__init__.py +0 -8
- 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/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 -36
- django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
- django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -27
- django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -144
- django_cfg/apps/payments/templates/payments/dashboard.html +0 -346
- django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
- django_cfg/apps/payments/urls_templates.py +0 -52
- django_cfg/apps/payments/utils/__init__.py +0 -45
- django_cfg/apps/payments/utils/billing_utils.py +0 -342
- django_cfg/apps/payments/utils/config_utils.py +0 -245
- 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 -62
- 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 -111
- 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 -312
- django_cfg/apps/payments/views/templates/base.py +0 -204
- 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 -164
- django_cfg/apps/payments/views/templates/qr_code.py +0 -174
- django_cfg/apps/payments/views/templates/stats.py +0 -240
- 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 -65
- django_cfg/core/integration.py +0 -160
- django_cfg/modules/django_currency/clients/coingecko_client.py +0 -257
- django_cfg/modules/django_currency/clients/yfinance_client.py +0 -246
- 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.29.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
- {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,137 +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
|
8
|
+
from typing import Dict, Any, Optional, List
|
9
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
|
10
13
|
|
11
|
-
|
14
|
+
|
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")
|
33
|
+
|
34
|
+
|
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")
|
12
50
|
|
13
51
|
|
14
|
-
class
|
15
|
-
"""
|
52
|
+
class BaseProvider(ABC):
|
53
|
+
"""
|
54
|
+
Abstract base class for payment providers.
|
55
|
+
|
56
|
+
Defines the unified interface that all providers must implement.
|
57
|
+
"""
|
16
58
|
|
17
|
-
def __init__(self, config:
|
18
|
-
"""
|
59
|
+
def __init__(self, config: ProviderConfig):
|
60
|
+
"""
|
61
|
+
Initialize provider with configuration.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
config: Provider configuration
|
65
|
+
"""
|
19
66
|
self.config = config
|
20
|
-
self.
|
21
|
-
self.
|
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
|
22
79
|
|
23
80
|
@abstractmethod
|
24
|
-
def create_payment(self,
|
81
|
+
def create_payment(self, request: PaymentRequest) -> ProviderResponse:
|
25
82
|
"""
|
26
|
-
Create
|
83
|
+
Create payment with provider.
|
27
84
|
|
28
85
|
Args:
|
29
|
-
|
30
|
-
currency: Payment currency
|
31
|
-
**kwargs: Additional parameters (order_id, description, etc.)
|
86
|
+
request: Payment creation request
|
32
87
|
|
33
88
|
Returns:
|
34
|
-
|
89
|
+
ProviderResponse: Provider response with payment details
|
35
90
|
"""
|
36
91
|
pass
|
37
92
|
|
38
93
|
@abstractmethod
|
39
|
-
def
|
94
|
+
def get_payment_status(self, provider_payment_id: str) -> ProviderResponse:
|
40
95
|
"""
|
41
|
-
|
96
|
+
Get payment status from provider.
|
42
97
|
|
43
98
|
Args:
|
44
|
-
|
99
|
+
provider_payment_id: Provider's payment ID
|
45
100
|
|
46
101
|
Returns:
|
47
|
-
|
102
|
+
ProviderResponse: Current payment status
|
48
103
|
"""
|
49
104
|
pass
|
50
105
|
|
51
106
|
@abstractmethod
|
52
|
-
def
|
107
|
+
def get_supported_currencies(self) -> ServiceOperationResult:
|
53
108
|
"""
|
54
|
-
|
109
|
+
Get list of supported currencies from provider.
|
55
110
|
|
56
|
-
Args:
|
57
|
-
payload: Webhook data from provider
|
58
|
-
|
59
111
|
Returns:
|
60
|
-
|
112
|
+
ServiceOperationResult: List of supported currencies
|
61
113
|
"""
|
62
114
|
pass
|
63
115
|
|
64
116
|
@abstractmethod
|
65
|
-
def
|
117
|
+
def validate_webhook(self, payload: Dict[str, Any], signature: str = None) -> ServiceOperationResult:
|
66
118
|
"""
|
67
|
-
|
119
|
+
Validate webhook from provider.
|
68
120
|
|
121
|
+
Args:
|
122
|
+
payload: Webhook payload
|
123
|
+
signature: Webhook signature (if any)
|
124
|
+
|
69
125
|
Returns:
|
70
|
-
|
126
|
+
ServiceOperationResult: Validation result
|
71
127
|
"""
|
72
128
|
pass
|
73
129
|
|
74
|
-
def
|
130
|
+
def get_exchange_rate(self, from_currency: str, to_currency: str) -> ServiceOperationResult:
|
75
131
|
"""
|
76
|
-
|
132
|
+
Get exchange rate from provider (optional).
|
77
133
|
|
78
134
|
Args:
|
79
|
-
|
80
|
-
|
135
|
+
from_currency: Source currency
|
136
|
+
to_currency: Target currency
|
81
137
|
|
82
138
|
Returns:
|
83
|
-
|
139
|
+
ServiceOperationResult: Exchange rate or not supported
|
84
140
|
"""
|
85
|
-
|
86
|
-
|
141
|
+
return ServiceOperationResult(
|
142
|
+
success=False,
|
143
|
+
message=f"Exchange rates not supported by {self.name}",
|
144
|
+
error_code="not_supported"
|
145
|
+
)
|
87
146
|
|
88
|
-
def
|
147
|
+
def health_check(self) -> ServiceOperationResult:
|
89
148
|
"""
|
90
|
-
|
149
|
+
Perform provider health check.
|
91
150
|
|
92
|
-
Args:
|
93
|
-
currency_from: Source currency
|
94
|
-
currency_to: Target currency
|
95
|
-
|
96
151
|
Returns:
|
97
|
-
|
152
|
+
ServiceOperationResult: Health check result
|
98
153
|
"""
|
99
|
-
|
100
|
-
|
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
|
+
)
|
101
185
|
|
102
|
-
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]:
|
103
193
|
"""
|
104
|
-
|
194
|
+
Make HTTP request to provider API.
|
105
195
|
|
106
196
|
Args:
|
107
|
-
|
108
|
-
|
197
|
+
method: HTTP method
|
198
|
+
endpoint: API endpoint
|
199
|
+
data: Request data
|
200
|
+
headers: Request headers
|
109
201
|
|
110
202
|
Returns:
|
111
|
-
Dict
|
203
|
+
Dict[str, Any]: Response data
|
204
|
+
|
205
|
+
Raises:
|
206
|
+
Exception: If request fails
|
112
207
|
"""
|
113
|
-
|
114
|
-
|
208
|
+
import requests
|
209
|
+
from requests.adapters import HTTPAdapter
|
210
|
+
from urllib3.util.retry import Retry
|
211
|
+
|
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()
|
261
|
+
|
262
|
+
try:
|
263
|
+
return response.json()
|
264
|
+
except ValueError:
|
265
|
+
# Non-JSON response
|
266
|
+
return {'raw_response': response.text, 'status_code': response.status_code}
|
115
267
|
|
116
|
-
def
|
268
|
+
def _create_provider_response(
|
269
|
+
self,
|
270
|
+
success: bool,
|
271
|
+
raw_response: Dict[str, Any],
|
272
|
+
**kwargs
|
273
|
+
) -> ProviderResponse:
|
117
274
|
"""
|
118
|
-
|
275
|
+
Create standardized provider response.
|
119
276
|
|
277
|
+
Args:
|
278
|
+
success: Operation success
|
279
|
+
raw_response: Raw provider response
|
280
|
+
**kwargs: Additional response fields
|
281
|
+
|
120
282
|
Returns:
|
121
|
-
|
122
|
-
"""
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
def
|
131
|
-
"""
|
132
|
-
return {
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
}
|
283
|
+
ProviderResponse: Standardized response
|
284
|
+
"""
|
285
|
+
return ProviderResponse(
|
286
|
+
provider=self.name,
|
287
|
+
success=success,
|
288
|
+
raw_response=raw_response,
|
289
|
+
**kwargs
|
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}')"
|