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,380 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
NowPayments provider implementation.
|
3
|
-
|
4
|
-
Enhanced crypto payment provider with minimal typing.
|
5
|
-
"""
|
6
|
-
|
7
|
-
import requests
|
8
|
-
import hashlib
|
9
|
-
import hmac
|
10
|
-
from typing import Optional, List
|
11
|
-
from decimal import Decimal
|
12
|
-
from datetime import datetime
|
13
|
-
from ..base import PaymentProvider
|
14
|
-
from ...internal_types import ProviderResponse, WebhookData, PaymentAmountEstimate, UniversalCurrency, UniversalCurrenciesResponse
|
15
|
-
from .models import NowPaymentsConfig
|
16
|
-
from django_cfg.modules.django_logger import get_logger
|
17
|
-
|
18
|
-
logger = get_logger("nowpayments")
|
19
|
-
|
20
|
-
|
21
|
-
class NowPaymentsProvider(PaymentProvider):
|
22
|
-
"""NowPayments cryptocurrency payment provider."""
|
23
|
-
|
24
|
-
# Map NowPayments status to universal status
|
25
|
-
STATUS_MAPPING = {
|
26
|
-
'waiting': 'pending',
|
27
|
-
'confirming': 'processing',
|
28
|
-
'confirmed': 'completed',
|
29
|
-
'sending': 'processing',
|
30
|
-
'partially_paid': 'pending',
|
31
|
-
'finished': 'completed',
|
32
|
-
'failed': 'failed',
|
33
|
-
'refunded': 'refunded',
|
34
|
-
'expired': 'expired'
|
35
|
-
}
|
36
|
-
|
37
|
-
def __init__(self, config: NowPaymentsConfig):
|
38
|
-
"""Initialize NowPayments provider."""
|
39
|
-
super().__init__(config)
|
40
|
-
self.config = config
|
41
|
-
self.api_key = config.api_key
|
42
|
-
# TEMP: Disable sandbox since sandbox registration site is down
|
43
|
-
# self.sandbox = config.sandbox
|
44
|
-
self.sandbox = False # Force production URL
|
45
|
-
self.ipn_secret = config.ipn_secret or ''
|
46
|
-
self.base_url = self._get_base_url()
|
47
|
-
|
48
|
-
# Configurable URLs
|
49
|
-
self.callback_url = config.callback_url
|
50
|
-
self.success_url = config.success_url
|
51
|
-
self.cancel_url = config.cancel_url
|
52
|
-
|
53
|
-
self.headers = {
|
54
|
-
'x-api-key': self.api_key.get_secret_value() if hasattr(self.api_key, 'get_secret_value') else str(self.api_key),
|
55
|
-
'Content-Type': 'application/json'
|
56
|
-
}
|
57
|
-
|
58
|
-
def _get_dynamic_callback_url(self) -> Optional[str]:
|
59
|
-
"""Get dynamic callback URL with ngrok support."""
|
60
|
-
try:
|
61
|
-
from api.config import config
|
62
|
-
|
63
|
-
# Try ngrok first (development)
|
64
|
-
ngrok_url = getattr(config, 'get_ngrok_url', lambda x: None)('/cfg/admin/django_cfg_payments/webhooks/nowpayments/')
|
65
|
-
if ngrok_url:
|
66
|
-
logger.info(f"Using ngrok webhook URL: {ngrok_url}")
|
67
|
-
return ngrok_url
|
68
|
-
|
69
|
-
# Fallback to configured callback URL
|
70
|
-
if self.callback_url:
|
71
|
-
logger.info(f"Using configured webhook URL: {self.callback_url}")
|
72
|
-
return self.callback_url
|
73
|
-
|
74
|
-
# Fallback to site URL
|
75
|
-
site_webhook = f"{config.site_url}/cfg/admin/django_cfg_payments/webhooks/nowpayments/"
|
76
|
-
logger.info(f"Using site webhook URL: {site_webhook}")
|
77
|
-
return site_webhook
|
78
|
-
|
79
|
-
except Exception as e:
|
80
|
-
logger.warning(f"Failed to get dynamic callback URL: {e}")
|
81
|
-
return self.callback_url
|
82
|
-
|
83
|
-
def _get_base_url(self) -> str:
|
84
|
-
"""Get base URL based on sandbox mode."""
|
85
|
-
if self.sandbox:
|
86
|
-
return 'https://api-sandbox.nowpayments.io/v1'
|
87
|
-
return 'https://api.nowpayments.io/v1'
|
88
|
-
|
89
|
-
def _make_request(self, method: str, endpoint: str, data: Optional[dict] = None) -> Optional[dict]:
|
90
|
-
"""Make HTTP request to NowPayments API with error handling."""
|
91
|
-
try:
|
92
|
-
url = f"{self.base_url}/{endpoint}"
|
93
|
-
|
94
|
-
response = requests.request(
|
95
|
-
method=method,
|
96
|
-
url=url,
|
97
|
-
headers=self.headers,
|
98
|
-
json=data,
|
99
|
-
timeout=30
|
100
|
-
)
|
101
|
-
|
102
|
-
response.raise_for_status()
|
103
|
-
return response.json()
|
104
|
-
|
105
|
-
except requests.exceptions.RequestException as e:
|
106
|
-
logger.error(f"NowPayments API request failed: {e}")
|
107
|
-
return None
|
108
|
-
except Exception as e:
|
109
|
-
logger.error(f"Unexpected error in NowPayments request: {e}")
|
110
|
-
return None
|
111
|
-
|
112
|
-
def create_payment(self, payment_data: dict) -> ProviderResponse:
|
113
|
-
"""Create payment via NowPayments API."""
|
114
|
-
try:
|
115
|
-
amount = Decimal(str(payment_data['amount']))
|
116
|
-
currency = payment_data['currency']
|
117
|
-
order_id = payment_data.get('order_id', f'payment_{int(amount * 100)}_{currency}')
|
118
|
-
|
119
|
-
payment_request = {
|
120
|
-
'price_amount': float(amount),
|
121
|
-
'price_currency': 'usd', # Base currency
|
122
|
-
'pay_currency': currency,
|
123
|
-
'order_id': order_id,
|
124
|
-
'order_description': payment_data.get('description', f'Payment {order_id}'),
|
125
|
-
}
|
126
|
-
|
127
|
-
# Add optional URLs
|
128
|
-
if self.success_url:
|
129
|
-
payment_request['success_url'] = self.success_url
|
130
|
-
if self.cancel_url:
|
131
|
-
payment_request['cancel_url'] = self.cancel_url
|
132
|
-
|
133
|
-
# Get dynamic callback URL with ngrok support
|
134
|
-
dynamic_callback_url = self._get_dynamic_callback_url()
|
135
|
-
if dynamic_callback_url:
|
136
|
-
payment_request['ipn_callback_url'] = dynamic_callback_url
|
137
|
-
|
138
|
-
response = self._make_request('POST', 'payment', payment_request)
|
139
|
-
|
140
|
-
if response:
|
141
|
-
return ProviderResponse(
|
142
|
-
success=True,
|
143
|
-
provider_payment_id=response.get('payment_id'),
|
144
|
-
payment_url=response.get('invoice_url'),
|
145
|
-
pay_address=response.get('pay_address'),
|
146
|
-
amount=Decimal(str(response.get('pay_amount', 0))),
|
147
|
-
currency=response.get('pay_currency'),
|
148
|
-
status='pending'
|
149
|
-
)
|
150
|
-
else:
|
151
|
-
return ProviderResponse(
|
152
|
-
success=False,
|
153
|
-
error_message='Failed to create payment'
|
154
|
-
)
|
155
|
-
|
156
|
-
except Exception as e:
|
157
|
-
logger.error(f"NowPayments create_payment error: {e}")
|
158
|
-
return ProviderResponse(
|
159
|
-
success=False,
|
160
|
-
error_message=str(e)
|
161
|
-
)
|
162
|
-
|
163
|
-
def check_payment_status(self, payment_id: str) -> ProviderResponse:
|
164
|
-
"""Check payment status via NowPayments API."""
|
165
|
-
try:
|
166
|
-
response = self._make_request('GET', f'payment/{payment_id}')
|
167
|
-
|
168
|
-
if response:
|
169
|
-
provider_status = response.get('payment_status', 'unknown')
|
170
|
-
universal_status = self.STATUS_MAPPING.get(provider_status, 'unknown')
|
171
|
-
|
172
|
-
return ProviderResponse(
|
173
|
-
success=True,
|
174
|
-
provider_payment_id=response.get('payment_id'),
|
175
|
-
status=universal_status,
|
176
|
-
pay_address=response.get('pay_address'),
|
177
|
-
amount=Decimal(str(response.get('pay_amount', 0))),
|
178
|
-
currency=response.get('pay_currency')
|
179
|
-
)
|
180
|
-
else:
|
181
|
-
return ProviderResponse(
|
182
|
-
success=False,
|
183
|
-
error_message='Payment not found'
|
184
|
-
)
|
185
|
-
|
186
|
-
except Exception as e:
|
187
|
-
logger.error(f"NowPayments check_payment_status error: {e}")
|
188
|
-
return ProviderResponse(
|
189
|
-
success=False,
|
190
|
-
error_message=str(e)
|
191
|
-
)
|
192
|
-
|
193
|
-
def process_webhook(self, payload: dict) -> WebhookData:
|
194
|
-
"""Process NowPayments webhook."""
|
195
|
-
try:
|
196
|
-
provider_status = payload.get('payment_status', 'unknown')
|
197
|
-
universal_status = self.STATUS_MAPPING.get(provider_status, 'unknown')
|
198
|
-
|
199
|
-
return WebhookData(
|
200
|
-
provider_payment_id=str(payload.get('payment_id', '')),
|
201
|
-
status=universal_status,
|
202
|
-
pay_amount=Decimal(str(payload.get('pay_amount', 0))),
|
203
|
-
actually_paid=Decimal(str(payload.get('actually_paid', 0))),
|
204
|
-
order_id=payload.get('order_id'),
|
205
|
-
signature=payload.get('signature')
|
206
|
-
)
|
207
|
-
|
208
|
-
except Exception as e:
|
209
|
-
logger.error(f"NowPayments webhook processing error: {e}")
|
210
|
-
raise
|
211
|
-
|
212
|
-
|
213
|
-
def get_parsed_currencies(self) -> UniversalCurrenciesResponse:
|
214
|
-
"""Get parsed and normalized currencies from NowPayments."""
|
215
|
-
try:
|
216
|
-
# Use full-currencies endpoint to get detailed currency info
|
217
|
-
response = self._make_request('GET', 'full-currencies')
|
218
|
-
|
219
|
-
if not response or 'currencies' not in response:
|
220
|
-
return UniversalCurrenciesResponse(currencies=[])
|
221
|
-
|
222
|
-
universal_currencies = []
|
223
|
-
|
224
|
-
for currency_data in response['currencies']:
|
225
|
-
if not currency_data.get('enable', True):
|
226
|
-
continue # Skip disabled currencies
|
227
|
-
|
228
|
-
provider_code = currency_data.get('code', '').upper()
|
229
|
-
if not provider_code:
|
230
|
-
continue
|
231
|
-
|
232
|
-
# Parse provider code into base currency + network using API data
|
233
|
-
currency_name = currency_data.get('name', '')
|
234
|
-
api_network = currency_data.get('network')
|
235
|
-
ticker = currency_data.get('ticker', '')
|
236
|
-
base_currency_code, network_code = self._parse_currency_code(provider_code, currency_name, api_network, ticker)
|
237
|
-
|
238
|
-
# Determine currency type
|
239
|
-
currency_type = 'fiat' if network_code is None else 'crypto'
|
240
|
-
|
241
|
-
universal_currency = UniversalCurrency(
|
242
|
-
provider_currency_code=provider_code,
|
243
|
-
base_currency_code=base_currency_code,
|
244
|
-
network_code=network_code,
|
245
|
-
name=currency_data.get('name', base_currency_code),
|
246
|
-
currency_type=currency_type,
|
247
|
-
is_enabled=currency_data.get('enable', True),
|
248
|
-
is_popular=currency_data.get('is_popular', False),
|
249
|
-
is_stable=currency_data.get('is_stable', False),
|
250
|
-
priority=currency_data.get('priority', 0),
|
251
|
-
logo_url=currency_data.get('logo_url', ''),
|
252
|
-
available_for_payment=currency_data.get('available_for_payment', True),
|
253
|
-
available_for_payout=currency_data.get('available_for_payout', True),
|
254
|
-
raw_data=currency_data
|
255
|
-
)
|
256
|
-
|
257
|
-
universal_currencies.append(universal_currency)
|
258
|
-
|
259
|
-
return UniversalCurrenciesResponse(currencies=universal_currencies)
|
260
|
-
|
261
|
-
except Exception as e:
|
262
|
-
logger.error(f"Error parsing currencies: {e}")
|
263
|
-
return UniversalCurrenciesResponse(currencies=[])
|
264
|
-
|
265
|
-
def _parse_currency_code(self, provider_code: str, currency_name: str, network_code: Optional[str] = None, ticker: str = '') -> tuple[str, Optional[str]]:
|
266
|
-
"""
|
267
|
-
Smart parsing using API data, prioritizing ticker field.
|
268
|
-
|
269
|
-
Uses ticker as primary source for base currency, then falls back to name parsing.
|
270
|
-
|
271
|
-
Examples:
|
272
|
-
- "1INCHBSC", "1Inch Network (BSC)", "bsc", "1inch" → ("1INCH", "bsc")
|
273
|
-
- "USDTERC20", "Tether USD (ERC-20)", "eth", "usdt" → ("USDT", "eth")
|
274
|
-
- "BTC", "Bitcoin", "btc", "btc" → ("BTC", "btc")
|
275
|
-
"""
|
276
|
-
# Priority 1: Use ticker if available and meaningful
|
277
|
-
if ticker and len(ticker.strip()) > 0:
|
278
|
-
base_currency = ticker.upper().strip()
|
279
|
-
return base_currency, network_code
|
280
|
-
|
281
|
-
# Priority 2: Extract from name using patterns
|
282
|
-
base_currency = self._extract_base_currency_from_name(currency_name, provider_code)
|
283
|
-
return base_currency, network_code
|
284
|
-
|
285
|
-
def _extract_base_currency_from_name(self, currency_name: str, fallback_code: str) -> str:
|
286
|
-
"""Extract base currency from human-readable name using real API patterns."""
|
287
|
-
if not currency_name:
|
288
|
-
return fallback_code
|
289
|
-
|
290
|
-
name_lower = currency_name.lower()
|
291
|
-
|
292
|
-
# Precise patterns from real NowPayments API data
|
293
|
-
precise_patterns = {
|
294
|
-
# Stablecoins - most common
|
295
|
-
'tether usd': 'USDT',
|
296
|
-
'tether (': 'USDT', # "Tether (Arbitrum One)"
|
297
|
-
'usd coin': 'USDC', # "USD Coin (Ethereum)"
|
298
|
-
'usd coin bridged': 'USDC', # "USD Coin Bridged (Polygon)"
|
299
|
-
'trueusd': 'TUSD', # "TrueUSD (Tron)"
|
300
|
-
|
301
|
-
# Major cryptocurrencies
|
302
|
-
'bitcoin': 'BTC',
|
303
|
-
'ethereum': 'ETH',
|
304
|
-
'cardano': 'ADA',
|
305
|
-
'dogecoin': 'DOGE',
|
306
|
-
'litecoin': 'LTC',
|
307
|
-
|
308
|
-
# Exchange tokens
|
309
|
-
'binance coin': 'BNB',
|
310
|
-
'bnb': 'BNB',
|
311
|
-
|
312
|
-
# Layer 1/2 tokens
|
313
|
-
'polygon': 'MATIC',
|
314
|
-
'avalanche': 'AVAX',
|
315
|
-
'solana': 'SOL',
|
316
|
-
'chainlink': 'LINK',
|
317
|
-
|
318
|
-
# Other stablecoins
|
319
|
-
'dai stablecoin': 'DAI',
|
320
|
-
'frax': 'FRAX'
|
321
|
-
}
|
322
|
-
|
323
|
-
# Check precise patterns first (most reliable)
|
324
|
-
for pattern, base in precise_patterns.items():
|
325
|
-
if pattern in name_lower:
|
326
|
-
return base
|
327
|
-
|
328
|
-
# Fallback patterns for edge cases
|
329
|
-
fallback_patterns = {
|
330
|
-
'usdt': 'USDT',
|
331
|
-
'usdc': 'USDC',
|
332
|
-
'tusd': 'TUSD',
|
333
|
-
'btc': 'BTC',
|
334
|
-
'eth ': 'ETH',
|
335
|
-
'ada': 'ADA',
|
336
|
-
'doge': 'DOGE',
|
337
|
-
'matic': 'MATIC'
|
338
|
-
}
|
339
|
-
|
340
|
-
for pattern, base in fallback_patterns.items():
|
341
|
-
if pattern in name_lower:
|
342
|
-
return base
|
343
|
-
|
344
|
-
# Last resort: use the provider code as-is
|
345
|
-
return fallback_code
|
346
|
-
|
347
|
-
|
348
|
-
def validate_webhook(self, payload: dict, headers: Optional[dict] = None) -> bool:
|
349
|
-
"""Validate NowPayments webhook signature."""
|
350
|
-
try:
|
351
|
-
if not self.ipn_secret:
|
352
|
-
logger.warning("IPN secret not configured, skipping webhook validation")
|
353
|
-
return True
|
354
|
-
|
355
|
-
if not headers:
|
356
|
-
logger.warning("No headers provided for webhook validation")
|
357
|
-
return False
|
358
|
-
|
359
|
-
# Get signature from headers
|
360
|
-
signature = headers.get('x-nowpayments-sig')
|
361
|
-
if not signature:
|
362
|
-
logger.warning("No signature found in webhook headers")
|
363
|
-
return False
|
364
|
-
|
365
|
-
# TODO: Implement proper HMAC signature validation
|
366
|
-
# This requires the raw payload body for proper validation
|
367
|
-
logger.info("Webhook signature validation placeholder")
|
368
|
-
return True
|
369
|
-
|
370
|
-
except Exception as e:
|
371
|
-
logger.error(f"Webhook validation error: {e}")
|
372
|
-
return False
|
373
|
-
|
374
|
-
def check_api_status(self) -> bool:
|
375
|
-
"""Check if NowPayments API is available."""
|
376
|
-
try:
|
377
|
-
response = self._make_request('GET', 'status')
|
378
|
-
return response is not None and response.get('message') == 'OK'
|
379
|
-
except:
|
380
|
-
return False
|
@@ -1,184 +0,0 @@
|
|
1
|
-
from pydantic import BaseModel, Field, ConfigDict, field_validator
|
2
|
-
from typing import Optional, List, Dict, Any
|
3
|
-
from decimal import Decimal
|
4
|
-
|
5
|
-
from ...internal_types import ProviderConfig
|
6
|
-
|
7
|
-
|
8
|
-
class StripeConfig(ProviderConfig):
|
9
|
-
"""Stripe provider configuration with Pydantic v2."""
|
10
|
-
|
11
|
-
webhook_secret: Optional[str] = Field(None, description="Webhook endpoint secret")
|
12
|
-
success_url: Optional[str] = Field(None, description="Payment success redirect URL")
|
13
|
-
cancel_url: Optional[str] = Field(None, description="Payment cancel redirect URL")
|
14
|
-
|
15
|
-
@field_validator('api_key')
|
16
|
-
@classmethod
|
17
|
-
def validate_api_key(cls, v: str) -> str:
|
18
|
-
if not v or not v.startswith(('sk_test_', 'sk_live_')):
|
19
|
-
raise ValueError("Stripe API key must start with sk_test_ or sk_live_")
|
20
|
-
return v
|
21
|
-
|
22
|
-
|
23
|
-
class StripeCurrency(BaseModel):
|
24
|
-
"""Stripe specific currency model."""
|
25
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
26
|
-
|
27
|
-
currency_code: str = Field(..., description="Currency symbol (e.g., USD, EUR)")
|
28
|
-
name: str = Field(..., description="Full currency name")
|
29
|
-
decimal_digits: int = Field(..., description="Number of decimal digits")
|
30
|
-
min_amount: Optional[Decimal] = Field(None, description="Minimum charge amount")
|
31
|
-
max_amount: Optional[Decimal] = Field(None, description="Maximum charge amount")
|
32
|
-
is_zero_decimal: bool = Field(False, description="Zero-decimal currency (like JPY)")
|
33
|
-
|
34
|
-
|
35
|
-
class StripeNetwork(BaseModel):
|
36
|
-
"""Stripe network model (not applicable for fiat payments)."""
|
37
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
38
|
-
|
39
|
-
code: str = Field(..., description="Network code (always 'stripe')")
|
40
|
-
name: str = Field(..., description="Network display name")
|
41
|
-
currency: str = Field(..., description="Currency this network belongs to")
|
42
|
-
|
43
|
-
|
44
|
-
class StripePaymentIntentRequest(BaseModel):
|
45
|
-
"""Stripe PaymentIntent creation request."""
|
46
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
47
|
-
|
48
|
-
amount: int = Field(..., description="Amount in smallest currency unit")
|
49
|
-
currency: str = Field(..., description="Three-letter ISO currency code")
|
50
|
-
payment_method_types: List[str] = Field(default=["card"], description="Payment method types")
|
51
|
-
confirm: bool = Field(False, description="Confirm PaymentIntent immediately")
|
52
|
-
capture_method: str = Field("automatic", description="Capture method")
|
53
|
-
confirmation_method: str = Field("automatic", description="Confirmation method")
|
54
|
-
description: Optional[str] = Field(None, description="Payment description")
|
55
|
-
metadata: Optional[Dict[str, str]] = Field(None, description="Metadata")
|
56
|
-
receipt_email: Optional[str] = Field(None, description="Receipt email")
|
57
|
-
return_url: Optional[str] = Field(None, description="Return URL")
|
58
|
-
success_url: Optional[str] = Field(None, description="Success URL")
|
59
|
-
cancel_url: Optional[str] = Field(None, description="Cancel URL")
|
60
|
-
|
61
|
-
|
62
|
-
class StripePaymentIntentResponse(BaseModel):
|
63
|
-
"""Stripe PaymentIntent response."""
|
64
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
65
|
-
|
66
|
-
id: str = Field(..., description="PaymentIntent ID")
|
67
|
-
object: str = Field(..., description="Object type")
|
68
|
-
amount: int = Field(..., description="Amount in smallest currency unit")
|
69
|
-
currency: str = Field(..., description="Currency code")
|
70
|
-
status: str = Field(..., description="PaymentIntent status")
|
71
|
-
client_secret: str = Field(..., description="Client secret for confirmation")
|
72
|
-
created: int = Field(..., description="Creation timestamp")
|
73
|
-
description: Optional[str] = Field(None, description="Payment description")
|
74
|
-
metadata: Dict[str, str] = Field(default_factory=dict, description="Metadata")
|
75
|
-
payment_method: Optional[str] = Field(None, description="Payment method ID")
|
76
|
-
receipt_email: Optional[str] = Field(None, description="Receipt email")
|
77
|
-
latest_charge: Optional[str] = Field(None, description="Latest charge ID")
|
78
|
-
|
79
|
-
|
80
|
-
class StripeWebhookEvent(BaseModel):
|
81
|
-
"""Stripe webhook event data."""
|
82
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
83
|
-
|
84
|
-
id: str = Field(..., description="Event ID")
|
85
|
-
object: str = Field(..., description="Object type")
|
86
|
-
api_version: str = Field(..., description="API version")
|
87
|
-
created: int = Field(..., description="Creation timestamp")
|
88
|
-
type: str = Field(..., description="Event type")
|
89
|
-
data: Dict[str, Any] = Field(..., description="Event data")
|
90
|
-
livemode: bool = Field(..., description="Live mode flag")
|
91
|
-
pending_webhooks: int = Field(..., description="Pending webhooks count")
|
92
|
-
request: Optional[Dict[str, Any]] = Field(None, description="Request info")
|
93
|
-
|
94
|
-
|
95
|
-
class StripeCharge(BaseModel):
|
96
|
-
"""Stripe charge object."""
|
97
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
98
|
-
|
99
|
-
id: str = Field(..., description="Charge ID")
|
100
|
-
object: str = Field(..., description="Object type")
|
101
|
-
amount: int = Field(..., description="Amount charged")
|
102
|
-
currency: str = Field(..., description="Currency code")
|
103
|
-
status: str = Field(..., description="Charge status")
|
104
|
-
created: int = Field(..., description="Creation timestamp")
|
105
|
-
description: Optional[str] = Field(None, description="Charge description")
|
106
|
-
metadata: Dict[str, str] = Field(default_factory=dict, description="Metadata")
|
107
|
-
payment_intent: Optional[str] = Field(None, description="PaymentIntent ID")
|
108
|
-
receipt_email: Optional[str] = Field(None, description="Receipt email")
|
109
|
-
receipt_url: Optional[str] = Field(None, description="Receipt URL")
|
110
|
-
|
111
|
-
|
112
|
-
class StripeCustomer(BaseModel):
|
113
|
-
"""Stripe customer object."""
|
114
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
115
|
-
|
116
|
-
id: str = Field(..., description="Customer ID")
|
117
|
-
object: str = Field(..., description="Object type")
|
118
|
-
created: int = Field(..., description="Creation timestamp")
|
119
|
-
email: Optional[str] = Field(None, description="Customer email")
|
120
|
-
name: Optional[str] = Field(None, description="Customer name")
|
121
|
-
phone: Optional[str] = Field(None, description="Customer phone")
|
122
|
-
metadata: Dict[str, str] = Field(default_factory=dict, description="Metadata")
|
123
|
-
|
124
|
-
|
125
|
-
class StripeError(BaseModel):
|
126
|
-
"""Stripe error response."""
|
127
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
128
|
-
|
129
|
-
type: str = Field(..., description="Error type")
|
130
|
-
code: Optional[str] = Field(None, description="Error code")
|
131
|
-
message: str = Field(..., description="Error message")
|
132
|
-
param: Optional[str] = Field(None, description="Parameter causing error")
|
133
|
-
decline_code: Optional[str] = Field(None, description="Decline code")
|
134
|
-
|
135
|
-
|
136
|
-
class StripeErrorResponse(BaseModel):
|
137
|
-
"""Stripe error response wrapper."""
|
138
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
139
|
-
|
140
|
-
error: StripeError = Field(..., description="Error details")
|
141
|
-
|
142
|
-
|
143
|
-
class StripeCurrenciesResponse(BaseModel):
|
144
|
-
"""Stripe supported currencies response."""
|
145
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
146
|
-
|
147
|
-
currencies: List[StripeCurrency] = Field(..., description="List of supported currencies")
|
148
|
-
|
149
|
-
|
150
|
-
class StripeWebhookEndpoint(BaseModel):
|
151
|
-
"""Stripe webhook endpoint configuration."""
|
152
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
153
|
-
|
154
|
-
id: str = Field(..., description="Webhook endpoint ID")
|
155
|
-
object: str = Field(..., description="Object type")
|
156
|
-
api_version: Optional[str] = Field(None, description="API version")
|
157
|
-
created: int = Field(..., description="Creation timestamp")
|
158
|
-
enabled_events: List[str] = Field(..., description="Enabled event types")
|
159
|
-
livemode: bool = Field(..., description="Live mode flag")
|
160
|
-
status: str = Field(..., description="Endpoint status")
|
161
|
-
url: str = Field(..., description="Endpoint URL")
|
162
|
-
|
163
|
-
|
164
|
-
# =============================================================================
|
165
|
-
# MONITORING & HEALTH CHECK MODELS
|
166
|
-
# =============================================================================
|
167
|
-
|
168
|
-
class StripeHealthErrorResponse(BaseModel):
|
169
|
-
"""Stripe API error response schema for health checks."""
|
170
|
-
model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
171
|
-
|
172
|
-
class StripeHealthError(BaseModel):
|
173
|
-
message: str = Field(..., description="Error message")
|
174
|
-
type: str = Field(..., description="Error type")
|
175
|
-
|
176
|
-
error: StripeHealthError = Field(..., description="Error details")
|
177
|
-
|
178
|
-
@field_validator('error')
|
179
|
-
@classmethod
|
180
|
-
def validate_auth_error(cls, v):
|
181
|
-
"""Validate this is an authentication error (meaning API is healthy)."""
|
182
|
-
if v.type != 'invalid_request_error':
|
183
|
-
raise ValueError(f"Expected auth error, got '{v.type}'")
|
184
|
-
return v
|
@@ -1,109 +0,0 @@
|
|
1
|
-
from typing import Dict, Any, Optional, List
|
2
|
-
from decimal import Decimal
|
3
|
-
|
4
|
-
from ..base import PaymentProvider
|
5
|
-
from ...internal_types import ProviderResponse, WebhookData
|
6
|
-
from .models import StripeConfig, StripeCurrency, StripeNetwork
|
7
|
-
from django_cfg.modules.django_logger import get_logger
|
8
|
-
|
9
|
-
logger = get_logger("stripe")
|
10
|
-
|
11
|
-
|
12
|
-
class StripeProvider(PaymentProvider):
|
13
|
-
"""Stripe payment provider implementation."""
|
14
|
-
|
15
|
-
name = "stripe"
|
16
|
-
|
17
|
-
def __init__(self, config: StripeConfig):
|
18
|
-
super().__init__(config)
|
19
|
-
self.config = config
|
20
|
-
self.api_key = config.api_key
|
21
|
-
self.webhook_secret = config.webhook_secret
|
22
|
-
self.base_url = "https://api.stripe.com/v1"
|
23
|
-
|
24
|
-
def create_payment(self, amount_usd: Decimal, currency_code: str, description: str = None, **kwargs) -> ProviderResponse:
|
25
|
-
"""Create a payment intent with Stripe."""
|
26
|
-
# TODO: Implement Stripe payment creation
|
27
|
-
return ProviderResponse(
|
28
|
-
success=False,
|
29
|
-
error_message="Stripe provider not implemented yet"
|
30
|
-
)
|
31
|
-
|
32
|
-
def check_payment_status(self, payment_id: str) -> ProviderResponse:
|
33
|
-
"""Check payment status from Stripe."""
|
34
|
-
# TODO: Implement Stripe payment status check
|
35
|
-
return ProviderResponse(
|
36
|
-
success=False,
|
37
|
-
error_message="Stripe provider not implemented yet"
|
38
|
-
)
|
39
|
-
|
40
|
-
def process_webhook(self, webhook_data: WebhookData) -> ProviderResponse:
|
41
|
-
"""Process Stripe webhook."""
|
42
|
-
# TODO: Implement Stripe webhook processing
|
43
|
-
return ProviderResponse(
|
44
|
-
success=False,
|
45
|
-
error_message="Stripe provider not implemented yet"
|
46
|
-
)
|
47
|
-
|
48
|
-
def validate_webhook_signature(self, payload: str, signature: str) -> bool:
|
49
|
-
"""Validate Stripe webhook signature."""
|
50
|
-
# TODO: Implement Stripe signature validation
|
51
|
-
return False
|
52
|
-
|
53
|
-
def get_supported_currencies(self) -> ProviderResponse:
|
54
|
-
"""Get supported currencies from Stripe."""
|
55
|
-
# Common fiat currencies supported by Stripe
|
56
|
-
currencies = [
|
57
|
-
StripeCurrency(
|
58
|
-
currency_code='USD',
|
59
|
-
name='US Dollar',
|
60
|
-
decimal_digits=2,
|
61
|
-
min_amount=Decimal('0.50'),
|
62
|
-
is_zero_decimal=False
|
63
|
-
),
|
64
|
-
StripeCurrency(
|
65
|
-
currency_code='EUR',
|
66
|
-
name='Euro',
|
67
|
-
decimal_digits=2,
|
68
|
-
min_amount=Decimal('0.50'),
|
69
|
-
is_zero_decimal=False
|
70
|
-
),
|
71
|
-
StripeCurrency(
|
72
|
-
currency_code='GBP',
|
73
|
-
name='British Pound',
|
74
|
-
decimal_digits=2,
|
75
|
-
min_amount=Decimal('0.30'),
|
76
|
-
is_zero_decimal=False
|
77
|
-
),
|
78
|
-
StripeCurrency(
|
79
|
-
currency_code='JPY',
|
80
|
-
name='Japanese Yen',
|
81
|
-
decimal_digits=0,
|
82
|
-
min_amount=Decimal('50'),
|
83
|
-
is_zero_decimal=True
|
84
|
-
),
|
85
|
-
]
|
86
|
-
|
87
|
-
return ProviderResponse(
|
88
|
-
success=True,
|
89
|
-
data={'currencies': [c.model_dump() for c in currencies]}
|
90
|
-
)
|
91
|
-
|
92
|
-
def get_supported_networks(self, currency_code: str = None) -> ProviderResponse:
|
93
|
-
"""Get supported networks (not applicable for Stripe fiat payments)."""
|
94
|
-
return ProviderResponse(
|
95
|
-
success=True,
|
96
|
-
data={'networks': {}}
|
97
|
-
)
|
98
|
-
|
99
|
-
def get_currency_network_mapping(self) -> Dict[str, List[str]]:
|
100
|
-
"""Get currency network mapping (not applicable for Stripe)."""
|
101
|
-
return {}
|
102
|
-
|
103
|
-
def check_api_status(self) -> Dict[str, Any]:
|
104
|
-
"""Check Stripe API status."""
|
105
|
-
# TODO: Implement actual API health check
|
106
|
-
return {
|
107
|
-
'status': 'unknown',
|
108
|
-
'message': 'Stripe provider not implemented yet'
|
109
|
-
}
|