django-cfg 1.3.7__py3-none-any.whl → 1.3.11__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/accounts/admin/__init__.py +24 -8
- django_cfg/apps/accounts/admin/activity_admin.py +146 -0
- django_cfg/apps/accounts/admin/filters.py +98 -22
- django_cfg/apps/accounts/admin/group_admin.py +86 -0
- django_cfg/apps/accounts/admin/inlines.py +42 -13
- django_cfg/apps/accounts/admin/otp_admin.py +115 -0
- django_cfg/apps/accounts/admin/registration_admin.py +173 -0
- django_cfg/apps/accounts/admin/resources.py +123 -19
- django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
- django_cfg/apps/accounts/admin/user_admin.py +362 -0
- django_cfg/apps/agents/admin/__init__.py +17 -4
- django_cfg/apps/agents/admin/execution_admin.py +204 -183
- django_cfg/apps/agents/admin/registry_admin.py +230 -255
- django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
- django_cfg/apps/agents/core/__init__.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +221 -0
- django_cfg/apps/agents/core/exceptions.py +14 -0
- django_cfg/apps/agents/core/orchestrator.py +18 -3
- django_cfg/apps/knowbase/admin/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
- django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
- django_cfg/apps/knowbase/admin/document_admin.py +269 -262
- django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
- django_cfg/apps/knowbase/config/settings.py +21 -4
- django_cfg/apps/knowbase/views/chat_views.py +3 -0
- django_cfg/apps/leads/admin/__init__.py +3 -1
- django_cfg/apps/leads/admin/leads_admin.py +235 -35
- django_cfg/apps/maintenance/admin/__init__.py +2 -2
- django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
- django_cfg/apps/maintenance/admin/log_admin.py +143 -61
- django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
- django_cfg/apps/maintenance/admin/site_admin.py +213 -352
- django_cfg/apps/newsletter/admin/__init__.py +29 -2
- django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
- django_cfg/apps/payments/admin/__init__.py +18 -27
- django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
- django_cfg/apps/payments/admin/balance_admin.py +166 -632
- django_cfg/apps/payments/admin/currencies_admin.py +235 -607
- django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
- django_cfg/apps/payments/admin/filters.py +83 -3
- django_cfg/apps/payments/admin/networks_admin.py +269 -0
- django_cfg/apps/payments/admin/payments_admin.py +183 -460
- django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
- django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
- django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
- django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
- django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
- django_cfg/apps/payments/config/__init__.py +14 -15
- django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
- django_cfg/apps/payments/config/helpers.py +8 -13
- django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
- django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
- django_cfg/apps/payments/middleware/api_access.py +32 -6
- django_cfg/apps/payments/migrations/0001_initial.py +33 -46
- django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
- django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
- django_cfg/apps/payments/models/balance.py +12 -0
- django_cfg/apps/payments/models/currencies.py +106 -32
- django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
- django_cfg/apps/payments/models/payments.py +94 -0
- django_cfg/apps/payments/services/core/base.py +4 -4
- django_cfg/apps/payments/services/core/currency_service.py +35 -28
- django_cfg/apps/payments/services/core/payment_service.py +266 -39
- django_cfg/apps/payments/services/providers/__init__.py +3 -0
- django_cfg/apps/payments/services/providers/base.py +303 -41
- django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
- django_cfg/apps/payments/services/providers/models/base.py +145 -0
- django_cfg/apps/payments/services/providers/models/providers.py +87 -0
- django_cfg/apps/payments/services/providers/models/universal.py +48 -0
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
- django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
- django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
- django_cfg/apps/payments/services/providers/registry.py +9 -37
- django_cfg/apps/payments/services/providers/sync_service.py +277 -0
- django_cfg/apps/payments/services/types/requests.py +19 -7
- django_cfg/apps/payments/signals/payment_signals.py +31 -2
- django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
- django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
- django_cfg/apps/payments/tasks/__init__.py +39 -0
- django_cfg/apps/payments/tasks/types.py +73 -0
- django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
- django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
- django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
- django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
- django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
- django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
- django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
- django_cfg/apps/payments/urls.py +3 -2
- django_cfg/apps/payments/urls_admin.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +8 -5
- django_cfg/apps/payments/views/overview/services.py +2 -2
- django_cfg/apps/payments/views/serializers/currencies.py +22 -8
- django_cfg/apps/support/admin/__init__.py +10 -1
- django_cfg/apps/support/admin/support_admin.py +338 -141
- django_cfg/apps/tasks/admin/__init__.py +11 -0
- django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
- django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
- django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
- django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
- django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
- django_cfg/apps/tasks/tasks/__init__.py +10 -0
- django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
- django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
- django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
- django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
- django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
- django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
- django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
- django_cfg/apps/tasks/urls.py +2 -2
- django_cfg/apps/tasks/urls_admin.py +2 -2
- django_cfg/apps/tasks/utils/__init__.py +1 -0
- django_cfg/apps/tasks/utils/simulator.py +356 -0
- django_cfg/apps/tasks/views/__init__.py +16 -0
- django_cfg/apps/tasks/views/api.py +569 -0
- django_cfg/apps/tasks/views/dashboard.py +58 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +10 -5
- django_cfg/core/generation.py +1 -1
- django_cfg/core/integration/__init__.py +21 -0
- django_cfg/management/commands/__init__.py +13 -1
- django_cfg/management/commands/migrate_all.py +9 -3
- django_cfg/management/commands/migrator.py +11 -6
- django_cfg/management/commands/rundramatiq.py +3 -2
- django_cfg/management/commands/rundramatiq_simulator.py +430 -0
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/models/api_keys.py +115 -0
- django_cfg/models/constance.py +0 -11
- django_cfg/models/payments.py +137 -3
- django_cfg/modules/django_admin/__init__.py +64 -0
- django_cfg/modules/django_admin/decorators/__init__.py +13 -0
- django_cfg/modules/django_admin/decorators/actions.py +106 -0
- django_cfg/modules/django_admin/decorators/display.py +106 -0
- django_cfg/modules/django_admin/mixins/__init__.py +14 -0
- django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
- django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
- django_cfg/modules/django_admin/models/__init__.py +20 -0
- django_cfg/modules/django_admin/models/action_models.py +33 -0
- django_cfg/modules/django_admin/models/badge_models.py +20 -0
- django_cfg/modules/django_admin/models/base.py +26 -0
- django_cfg/modules/django_admin/models/display_models.py +31 -0
- django_cfg/modules/django_admin/utils/badges.py +159 -0
- django_cfg/modules/django_admin/utils/displays.py +247 -0
- django_cfg/modules/django_currency/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
- django_cfg/modules/django_currency/core/converter.py +12 -12
- django_cfg/modules/django_currency/database/__init__.py +2 -2
- django_cfg/modules/django_currency/database/database_loader.py +93 -42
- django_cfg/modules/django_llm/llm/client.py +10 -2
- django_cfg/modules/django_tasks.py +54 -21
- django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
- django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
- django_cfg/modules/django_unfold/dashboard.py +14 -13
- django_cfg/modules/django_unfold/models/config.py +1 -1
- django_cfg/registry/core.py +7 -9
- django_cfg/registry/third_party.py +2 -2
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
- django_cfg/apps/accounts/admin/activity.py +0 -96
- django_cfg/apps/accounts/admin/group.py +0 -17
- django_cfg/apps/accounts/admin/otp.py +0 -59
- django_cfg/apps/accounts/admin/registration_source.py +0 -97
- django_cfg/apps/accounts/admin/twilio_response.py +0 -227
- django_cfg/apps/accounts/admin/user.py +0 -300
- django_cfg/apps/agents/core/agent.py +0 -281
- django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
- django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
- django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
- django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
- django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
- django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
- django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
- django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
- django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
- django_cfg/apps/payments/config/constance/__init__.py +0 -22
- django_cfg/apps/payments/config/constance/config_service.py +0 -123
- django_cfg/apps/payments/config/constance/fields.py +0 -69
- django_cfg/apps/payments/config/constance/settings.py +0 -160
- django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
- django_cfg/apps/tasks/admin.py +0 -320
- django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
- django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
- django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
- django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
- django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
- django_cfg/apps/tasks/templates/tasks/base.html +0 -96
- django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
- django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
- django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
- django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
- django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
- django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
- django_cfg/apps/tasks/views.py +0 -461
- django_cfg/management/commands/auto_generate.py +0 -486
- django_cfg/middleware/static_nocache.py +0 -55
- django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
- /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -5,48 +5,13 @@ 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 Dict, Any, Optional
|
8
|
+
from typing import Dict, Any, Optional
|
9
9
|
from decimal import Decimal
|
10
|
-
|
10
|
+
import requests
|
11
|
+
from django.utils import timezone
|
11
12
|
from django_cfg.modules.django_logger import get_logger
|
12
13
|
from ..types import ProviderResponse, ServiceOperationResult
|
13
|
-
|
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")
|
14
|
+
from .models import ProviderConfig, PaymentRequest, WithdrawalRequest
|
50
15
|
|
51
16
|
|
52
17
|
class BaseProvider(ABC):
|
@@ -75,7 +40,90 @@ class BaseProvider(ABC):
|
|
75
40
|
@property
|
76
41
|
def is_sandbox(self) -> bool:
|
77
42
|
"""Check if provider is in sandbox mode."""
|
78
|
-
return self.config.
|
43
|
+
return self.config.sandbox_mode
|
44
|
+
|
45
|
+
# Provider configuration methods (to be overridden by specific providers)
|
46
|
+
def get_fee_percentage(self, currency_code: str = None, currency_type: str = None) -> Decimal:
|
47
|
+
"""
|
48
|
+
Get fee percentage for currency.
|
49
|
+
|
50
|
+
Args:
|
51
|
+
currency_code: Currency code (e.g., 'BTC', 'ETH')
|
52
|
+
currency_type: Currency type ('fiat', 'crypto')
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
Fee percentage as decimal (0.005 = 0.5%)
|
56
|
+
"""
|
57
|
+
return Decimal('0.005') # Default 0.5%
|
58
|
+
|
59
|
+
def get_fixed_fee_usd(self, currency_code: str = None, currency_type: str = None) -> Decimal:
|
60
|
+
"""
|
61
|
+
Get fixed fee in USD for currency.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
currency_code: Currency code (e.g., 'BTC', 'ETH')
|
65
|
+
currency_type: Currency type ('fiat', 'crypto')
|
66
|
+
|
67
|
+
Returns:
|
68
|
+
Fixed fee in USD
|
69
|
+
"""
|
70
|
+
return Decimal('0.0') # Default no fixed fee
|
71
|
+
|
72
|
+
def get_min_amount_usd(self, currency_code: str = None, currency_type: str = None, is_stable: bool = False) -> Decimal:
|
73
|
+
"""
|
74
|
+
Get minimum amount in USD for currency.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
currency_code: Currency code (e.g., 'BTC', 'ETH')
|
78
|
+
currency_type: Currency type ('fiat', 'crypto')
|
79
|
+
is_stable: Whether currency is a stablecoin
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
Minimum amount in USD
|
83
|
+
"""
|
84
|
+
if currency_type == 'fiat':
|
85
|
+
return Decimal('1.0')
|
86
|
+
elif is_stable:
|
87
|
+
return Decimal('0.01')
|
88
|
+
else:
|
89
|
+
return Decimal('0.000001')
|
90
|
+
|
91
|
+
def get_max_amount_usd(self, currency_code: str = None, currency_type: str = None) -> Decimal:
|
92
|
+
"""
|
93
|
+
Get maximum amount in USD for currency.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
currency_code: Currency code (e.g., 'BTC', 'ETH')
|
97
|
+
currency_type: Currency type ('fiat', 'crypto')
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
Maximum amount in USD
|
101
|
+
"""
|
102
|
+
return Decimal('1000000.0') # Default 1M USD
|
103
|
+
|
104
|
+
def get_confirmation_blocks(self, network_code: str) -> int:
|
105
|
+
"""
|
106
|
+
Get confirmation blocks for network.
|
107
|
+
|
108
|
+
Args:
|
109
|
+
network_code: Network code (e.g., 'btc', 'eth')
|
110
|
+
|
111
|
+
Returns:
|
112
|
+
Number of confirmation blocks
|
113
|
+
"""
|
114
|
+
return 1 # Default 1 confirmation
|
115
|
+
|
116
|
+
def get_network_name(self, network_code: str) -> str:
|
117
|
+
"""
|
118
|
+
Get human-readable network name.
|
119
|
+
|
120
|
+
Args:
|
121
|
+
network_code: Network code (e.g., 'btc', 'eth')
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
Human-readable network name
|
125
|
+
"""
|
126
|
+
return network_code.upper() if network_code else 'Unknown'
|
79
127
|
|
80
128
|
@abstractmethod
|
81
129
|
def create_payment(self, request: PaymentRequest) -> ProviderResponse:
|
@@ -103,6 +151,61 @@ class BaseProvider(ABC):
|
|
103
151
|
"""
|
104
152
|
pass
|
105
153
|
|
154
|
+
def refresh_payment_status(self, provider_payment_id: str, force_update: bool = True) -> ProviderResponse:
|
155
|
+
"""
|
156
|
+
Refresh payment status with enhanced error handling and caching control.
|
157
|
+
|
158
|
+
This method provides additional functionality over get_payment_status:
|
159
|
+
- Enhanced error handling
|
160
|
+
- Optional caching control
|
161
|
+
- Detailed logging
|
162
|
+
|
163
|
+
Args:
|
164
|
+
provider_payment_id: Provider's payment ID
|
165
|
+
force_update: Whether to bypass cache and force fresh data
|
166
|
+
|
167
|
+
Returns:
|
168
|
+
ProviderResponse: Current payment status with enhanced metadata
|
169
|
+
"""
|
170
|
+
self.logger.info(f"Refreshing payment status for {provider_payment_id}", extra={
|
171
|
+
'provider': self.name,
|
172
|
+
'payment_id': provider_payment_id,
|
173
|
+
'force_update': force_update
|
174
|
+
})
|
175
|
+
|
176
|
+
try:
|
177
|
+
# Call the provider-specific implementation
|
178
|
+
result = self.get_payment_status(provider_payment_id)
|
179
|
+
|
180
|
+
# Add refresh metadata
|
181
|
+
if result.success and hasattr(result, 'raw_response') and result.raw_response:
|
182
|
+
result.raw_response['_refresh_metadata'] = {
|
183
|
+
'refreshed_at': timezone.now().isoformat(),
|
184
|
+
'provider': self.name,
|
185
|
+
'force_update': force_update
|
186
|
+
}
|
187
|
+
|
188
|
+
self.logger.info(f"Payment status refreshed successfully", extra={
|
189
|
+
'provider': self.name,
|
190
|
+
'payment_id': provider_payment_id,
|
191
|
+
'status': getattr(result, 'status', 'unknown')
|
192
|
+
})
|
193
|
+
|
194
|
+
return result
|
195
|
+
|
196
|
+
except Exception as e:
|
197
|
+
self.logger.error(f"Failed to refresh payment status", extra={
|
198
|
+
'provider': self.name,
|
199
|
+
'payment_id': provider_payment_id,
|
200
|
+
'error': str(e)
|
201
|
+
})
|
202
|
+
|
203
|
+
return ProviderResponse(
|
204
|
+
success=False,
|
205
|
+
error_message=f"Failed to refresh payment status: {str(e)}",
|
206
|
+
raw_response={'error': str(e), 'provider': self.name}
|
207
|
+
)
|
208
|
+
|
106
209
|
@abstractmethod
|
107
210
|
def get_supported_currencies(self) -> ServiceOperationResult:
|
108
211
|
"""
|
@@ -113,6 +216,16 @@ class BaseProvider(ABC):
|
|
113
216
|
"""
|
114
217
|
pass
|
115
218
|
|
219
|
+
@abstractmethod
|
220
|
+
def sync_currencies_to_db(self):
|
221
|
+
"""
|
222
|
+
Sync currencies from provider API to database.
|
223
|
+
|
224
|
+
Returns:
|
225
|
+
CurrencySyncResult: Synchronization result
|
226
|
+
"""
|
227
|
+
pass
|
228
|
+
|
116
229
|
@abstractmethod
|
117
230
|
def validate_webhook(self, payload: Dict[str, Any], signature: str = None) -> ServiceOperationResult:
|
118
231
|
"""
|
@@ -127,6 +240,129 @@ class BaseProvider(ABC):
|
|
127
240
|
"""
|
128
241
|
pass
|
129
242
|
|
243
|
+
# Withdrawal/Payout Methods
|
244
|
+
|
245
|
+
def supports_withdrawals(self) -> bool:
|
246
|
+
"""
|
247
|
+
Check if provider supports withdrawals/payouts.
|
248
|
+
|
249
|
+
Returns:
|
250
|
+
bool: True if provider supports withdrawals
|
251
|
+
"""
|
252
|
+
return False # Default: most payment processors don't support withdrawals
|
253
|
+
|
254
|
+
def create_withdrawal(self, request: WithdrawalRequest) -> ProviderResponse:
|
255
|
+
"""
|
256
|
+
Create withdrawal/payout request with provider.
|
257
|
+
|
258
|
+
Args:
|
259
|
+
request: Withdrawal creation request
|
260
|
+
|
261
|
+
Returns:
|
262
|
+
ProviderResponse: Provider response with withdrawal details
|
263
|
+
|
264
|
+
Raises:
|
265
|
+
NotImplementedError: If provider doesn't support withdrawals
|
266
|
+
"""
|
267
|
+
if not self.supports_withdrawals():
|
268
|
+
return ProviderResponse(
|
269
|
+
success=False,
|
270
|
+
error_message=f"Provider {self.name} does not support withdrawals",
|
271
|
+
raw_response={'error': 'withdrawals_not_supported'}
|
272
|
+
)
|
273
|
+
|
274
|
+
raise NotImplementedError("Subclasses must implement create_withdrawal if they support withdrawals")
|
275
|
+
|
276
|
+
def get_withdrawal_status(self, provider_withdrawal_id: str) -> ProviderResponse:
|
277
|
+
"""
|
278
|
+
Get withdrawal status from provider.
|
279
|
+
|
280
|
+
Args:
|
281
|
+
provider_withdrawal_id: Provider's withdrawal ID
|
282
|
+
|
283
|
+
Returns:
|
284
|
+
ProviderResponse: Current withdrawal status
|
285
|
+
|
286
|
+
Raises:
|
287
|
+
NotImplementedError: If provider doesn't support withdrawals
|
288
|
+
"""
|
289
|
+
if not self.supports_withdrawals():
|
290
|
+
return ProviderResponse(
|
291
|
+
success=False,
|
292
|
+
error_message=f"Provider {self.name} does not support withdrawals",
|
293
|
+
raw_response={'error': 'withdrawals_not_supported'}
|
294
|
+
)
|
295
|
+
|
296
|
+
raise NotImplementedError("Subclasses must implement get_withdrawal_status if they support withdrawals")
|
297
|
+
|
298
|
+
def cancel_withdrawal(self, provider_withdrawal_id: str) -> ProviderResponse:
|
299
|
+
"""
|
300
|
+
Cancel pending withdrawal.
|
301
|
+
|
302
|
+
Args:
|
303
|
+
provider_withdrawal_id: Provider's withdrawal ID
|
304
|
+
|
305
|
+
Returns:
|
306
|
+
ProviderResponse: Cancellation result
|
307
|
+
|
308
|
+
Raises:
|
309
|
+
NotImplementedError: If provider doesn't support withdrawal cancellation
|
310
|
+
"""
|
311
|
+
if not self.supports_withdrawals():
|
312
|
+
return ProviderResponse(
|
313
|
+
success=False,
|
314
|
+
error_message=f"Provider {self.name} does not support withdrawals",
|
315
|
+
raw_response={'error': 'withdrawals_not_supported'}
|
316
|
+
)
|
317
|
+
|
318
|
+
return ProviderResponse(
|
319
|
+
success=False,
|
320
|
+
error_message=f"Provider {self.name} does not support withdrawal cancellation",
|
321
|
+
raw_response={'error': 'withdrawal_cancellation_not_supported'}
|
322
|
+
)
|
323
|
+
|
324
|
+
def get_withdrawal_fees(self, currency_code: str) -> ServiceOperationResult:
|
325
|
+
"""
|
326
|
+
Get withdrawal fees for specific currency.
|
327
|
+
|
328
|
+
Args:
|
329
|
+
currency_code: Currency code
|
330
|
+
|
331
|
+
Returns:
|
332
|
+
ServiceOperationResult: Fee information or not supported
|
333
|
+
"""
|
334
|
+
if not self.supports_withdrawals():
|
335
|
+
return ServiceOperationResult(
|
336
|
+
success=False,
|
337
|
+
message=f"Provider {self.name} does not support withdrawals"
|
338
|
+
)
|
339
|
+
|
340
|
+
return ServiceOperationResult(
|
341
|
+
success=False,
|
342
|
+
message="Withdrawal fee information not available"
|
343
|
+
)
|
344
|
+
|
345
|
+
def get_minimum_withdrawal_amount(self, currency_code: str) -> ServiceOperationResult:
|
346
|
+
"""
|
347
|
+
Get minimum withdrawal amount for specific currency.
|
348
|
+
|
349
|
+
Args:
|
350
|
+
currency_code: Currency code
|
351
|
+
|
352
|
+
Returns:
|
353
|
+
ServiceOperationResult: Minimum amount or not supported
|
354
|
+
"""
|
355
|
+
if not self.supports_withdrawals():
|
356
|
+
return ServiceOperationResult(
|
357
|
+
success=False,
|
358
|
+
message=f"Provider {self.name} does not support withdrawals"
|
359
|
+
)
|
360
|
+
|
361
|
+
return ServiceOperationResult(
|
362
|
+
success=False,
|
363
|
+
message="Minimum withdrawal amount information not available"
|
364
|
+
)
|
365
|
+
|
130
366
|
def get_exchange_rate(self, from_currency: str, to_currency: str) -> ServiceOperationResult:
|
131
367
|
"""
|
132
368
|
Get exchange rate from provider (optional).
|
@@ -257,7 +493,33 @@ class BaseProvider(ABC):
|
|
257
493
|
})
|
258
494
|
|
259
495
|
# Handle response
|
260
|
-
|
496
|
+
try:
|
497
|
+
response.raise_for_status()
|
498
|
+
except requests.exceptions.HTTPError as e:
|
499
|
+
# Log the error with response content for debugging
|
500
|
+
error_content = response.text if response.text else "No response content"
|
501
|
+
self.logger.error(f"HTTP {response.status_code} error from {self.name}", extra={
|
502
|
+
'status_code': response.status_code,
|
503
|
+
'error_content': error_content[:500], # Limit content length
|
504
|
+
'url': response.url
|
505
|
+
})
|
506
|
+
|
507
|
+
# Handle specific HTTP errors
|
508
|
+
if response.status_code == 403:
|
509
|
+
if "blocked" in error_content.lower() or "nowpayments.io" in error_content:
|
510
|
+
raise Exception(f"IP address blocked by {self.name}. Please contact {self.name} support or use a different IP/VPN.")
|
511
|
+
else:
|
512
|
+
raise Exception(f"Access forbidden by {self.name}. Check API key and permissions.")
|
513
|
+
elif response.status_code == 401:
|
514
|
+
raise Exception(f"Authentication failed with {self.name}. Check API key.")
|
515
|
+
elif response.status_code == 400:
|
516
|
+
raise Exception(f"Bad request to {self.name}: {error_content[:200]}")
|
517
|
+
elif response.status_code == 429:
|
518
|
+
raise Exception(f"Rate limit exceeded for {self.name}. Please try again later.")
|
519
|
+
elif response.status_code >= 500:
|
520
|
+
raise Exception(f"{self.name} server error ({response.status_code}). Please try again later.")
|
521
|
+
else:
|
522
|
+
raise Exception(f"HTTP {response.status_code} error from {self.name}: {error_content[:200]}")
|
261
523
|
|
262
524
|
try:
|
263
525
|
return response.json()
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"""
|
2
|
+
Universal provider models for Universal Payment System v2.0.
|
3
|
+
|
4
|
+
Common models used across all payment providers.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .base import (
|
8
|
+
ProviderConfig,
|
9
|
+
PaymentRequest,
|
10
|
+
WithdrawalRequest,
|
11
|
+
ProviderMetadata,
|
12
|
+
ProviderType,
|
13
|
+
ProviderStatus
|
14
|
+
)
|
15
|
+
from .universal import (
|
16
|
+
UniversalCurrency,
|
17
|
+
UniversalCurrenciesResponse,
|
18
|
+
CurrencySyncResult
|
19
|
+
)
|
20
|
+
from .providers import (
|
21
|
+
ProviderEnum,
|
22
|
+
PROVIDER_METADATA
|
23
|
+
)
|
24
|
+
|
25
|
+
__all__ = [
|
26
|
+
# Base models
|
27
|
+
'ProviderConfig',
|
28
|
+
'PaymentRequest',
|
29
|
+
'WithdrawalRequest',
|
30
|
+
'ProviderMetadata',
|
31
|
+
'ProviderType',
|
32
|
+
'ProviderStatus',
|
33
|
+
|
34
|
+
# Universal models
|
35
|
+
'UniversalCurrency',
|
36
|
+
'UniversalCurrenciesResponse',
|
37
|
+
'CurrencySyncResult',
|
38
|
+
|
39
|
+
# Provider definitions
|
40
|
+
'ProviderEnum',
|
41
|
+
'PROVIDER_METADATA'
|
42
|
+
]
|
@@ -0,0 +1,145 @@
|
|
1
|
+
"""
|
2
|
+
Base provider models for Universal Payment System v2.0.
|
3
|
+
|
4
|
+
Core Pydantic models for provider configuration and requests.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from typing import Dict, Any, Optional, List
|
8
|
+
from decimal import Decimal
|
9
|
+
from pydantic import BaseModel, Field, ConfigDict
|
10
|
+
from enum import Enum
|
11
|
+
|
12
|
+
|
13
|
+
class ProviderType(str, Enum):
|
14
|
+
"""Provider type classification."""
|
15
|
+
|
16
|
+
CRYPTO = "crypto"
|
17
|
+
FIAT = "fiat"
|
18
|
+
HYBRID = "hybrid" # Supports both fiat and crypto
|
19
|
+
|
20
|
+
|
21
|
+
class ProviderStatus(str, Enum):
|
22
|
+
"""Provider operational status."""
|
23
|
+
|
24
|
+
ACTIVE = "active"
|
25
|
+
MAINTENANCE = "maintenance"
|
26
|
+
DEPRECATED = "deprecated"
|
27
|
+
DISABLED = "disabled"
|
28
|
+
|
29
|
+
|
30
|
+
class ProviderConfig(BaseModel):
|
31
|
+
"""
|
32
|
+
Base provider configuration with Pydantic v2.
|
33
|
+
|
34
|
+
Common configuration fields for all payment providers.
|
35
|
+
"""
|
36
|
+
model_config = ConfigDict(
|
37
|
+
validate_assignment=True,
|
38
|
+
extra="forbid",
|
39
|
+
str_strip_whitespace=True,
|
40
|
+
frozen=False
|
41
|
+
)
|
42
|
+
|
43
|
+
provider_name: str = Field(..., description="Provider name")
|
44
|
+
api_key: str = Field(..., description="Provider API key")
|
45
|
+
api_url: str = Field(..., description="Provider API URL")
|
46
|
+
enabled: bool = Field(default=True, description="Whether provider is enabled")
|
47
|
+
sandbox_mode: bool = Field(default=False, description="Sandbox mode")
|
48
|
+
timeout: int = Field(default=30, ge=5, le=300, description="Request timeout in seconds")
|
49
|
+
retry_attempts: int = Field(default=3, ge=0, le=10, description="Number of retry attempts")
|
50
|
+
retry_delay: int = Field(default=5, ge=1, le=60, description="Delay between retries in seconds")
|
51
|
+
min_amount_usd: float = Field(default=1.0, ge=0.01, description="Minimum amount in USD")
|
52
|
+
max_amount_usd: float = Field(default=50000.0, ge=1.0, description="Maximum amount in USD")
|
53
|
+
supported_currencies: List[str] = Field(default_factory=list, description="Supported currencies")
|
54
|
+
webhook_secret: Optional[str] = Field(None, description="Webhook secret for validation")
|
55
|
+
|
56
|
+
|
57
|
+
class PaymentRequest(BaseModel):
|
58
|
+
"""
|
59
|
+
Universal payment request for providers with Pydantic v2.
|
60
|
+
|
61
|
+
Standardized payment creation request across all providers.
|
62
|
+
"""
|
63
|
+
model_config = ConfigDict(
|
64
|
+
validate_assignment=True,
|
65
|
+
extra="forbid",
|
66
|
+
str_strip_whitespace=True
|
67
|
+
)
|
68
|
+
|
69
|
+
amount_usd: float = Field(..., gt=0, description="Amount in USD")
|
70
|
+
currency_code: str = Field(..., min_length=3, max_length=10, description="Currency code")
|
71
|
+
order_id: str = Field(..., min_length=1, max_length=100, description="Internal order/payment ID")
|
72
|
+
callback_url: Optional[str] = Field(None, description="Success callback URL")
|
73
|
+
cancel_url: Optional[str] = Field(None, description="Cancel URL")
|
74
|
+
description: Optional[str] = Field(None, max_length=500, description="Payment description")
|
75
|
+
customer_email: Optional[str] = Field(None, description="Customer email")
|
76
|
+
metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
|
77
|
+
|
78
|
+
|
79
|
+
class WithdrawalRequest(BaseModel):
|
80
|
+
"""
|
81
|
+
Universal withdrawal request for providers with Pydantic v2.
|
82
|
+
|
83
|
+
Standardized withdrawal/payout request across all providers.
|
84
|
+
"""
|
85
|
+
model_config = ConfigDict(
|
86
|
+
validate_assignment=True,
|
87
|
+
extra="forbid",
|
88
|
+
str_strip_whitespace=True
|
89
|
+
)
|
90
|
+
|
91
|
+
amount: float = Field(..., gt=0, description="Withdrawal amount in crypto currency")
|
92
|
+
currency_code: str = Field(..., min_length=3, max_length=10, description="Cryptocurrency code")
|
93
|
+
destination_address: str = Field(..., min_length=10, description="Destination wallet address")
|
94
|
+
withdrawal_id: str = Field(..., min_length=1, max_length=100, description="Internal withdrawal ID")
|
95
|
+
callback_url: Optional[str] = Field(None, description="Withdrawal status callback URL")
|
96
|
+
description: Optional[str] = Field(None, max_length=500, description="Withdrawal description")
|
97
|
+
extra_id: Optional[str] = Field(None, description="Extra ID for destination (memo, tag, etc.)")
|
98
|
+
priority: Optional[str] = Field(default="normal", description="Transaction priority (low, normal, high)")
|
99
|
+
|
100
|
+
metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
|
101
|
+
|
102
|
+
|
103
|
+
class ProviderMetadata(BaseModel):
|
104
|
+
"""
|
105
|
+
Provider metadata with classification and features.
|
106
|
+
|
107
|
+
Contains provider-specific information for routing and display.
|
108
|
+
"""
|
109
|
+
model_config = ConfigDict(
|
110
|
+
validate_assignment=True,
|
111
|
+
extra="forbid",
|
112
|
+
frozen=True # Metadata should be immutable
|
113
|
+
)
|
114
|
+
|
115
|
+
name: str = Field(..., description="Human-readable provider name")
|
116
|
+
provider_type: ProviderType = Field(..., description="Provider type (crypto/fiat/hybrid)")
|
117
|
+
status: ProviderStatus = Field(default=ProviderStatus.ACTIVE, description="Provider status")
|
118
|
+
priority: int = Field(default=100, ge=0, le=1000, description="Provider priority (lower = higher priority)")
|
119
|
+
|
120
|
+
# Feature flags
|
121
|
+
supports_fiat: bool = Field(default=False, description="Supports fiat currencies")
|
122
|
+
supports_crypto: bool = Field(default=True, description="Supports cryptocurrencies")
|
123
|
+
supports_webhooks: bool = Field(default=True, description="Supports webhook notifications")
|
124
|
+
supports_refunds: bool = Field(default=False, description="Supports payment refunds")
|
125
|
+
supports_partial_payments: bool = Field(default=False, description="Supports partial payments")
|
126
|
+
|
127
|
+
# Limits and fees
|
128
|
+
min_amount_usd: float = Field(default=1.0, ge=0.01, description="Minimum payment amount in USD")
|
129
|
+
max_amount_usd: float = Field(default=50000.0, ge=1.0, description="Maximum payment amount in USD")
|
130
|
+
fee_percentage: float = Field(default=0.0, ge=0.0, le=100.0, description="Fee percentage")
|
131
|
+
fixed_fee_usd: float = Field(default=0.0, ge=0.0, description="Fixed fee in USD")
|
132
|
+
|
133
|
+
# Geographic and regulatory
|
134
|
+
supported_countries: List[str] = Field(default_factory=list, description="Supported country codes")
|
135
|
+
restricted_countries: List[str] = Field(default_factory=list, description="Restricted country codes")
|
136
|
+
requires_kyc: bool = Field(default=False, description="Requires KYC verification")
|
137
|
+
|
138
|
+
# Technical details
|
139
|
+
api_version: str = Field(default="v1", description="API version")
|
140
|
+
documentation_url: Optional[str] = Field(None, description="API documentation URL")
|
141
|
+
status_page_url: Optional[str] = Field(None, description="Provider status page URL")
|
142
|
+
|
143
|
+
# Additional metadata
|
144
|
+
tags: List[str] = Field(default_factory=list, description="Provider tags for categorization")
|
145
|
+
description: Optional[str] = Field(None, max_length=500, description="Provider description")
|
@@ -0,0 +1,87 @@
|
|
1
|
+
"""
|
2
|
+
Provider enums and metadata for Universal Payment System v2.0.
|
3
|
+
|
4
|
+
Provider definitions with comprehensive metadata.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from enum import Enum
|
8
|
+
from typing import List, Dict
|
9
|
+
from .base import ProviderMetadata, ProviderType, ProviderStatus
|
10
|
+
|
11
|
+
|
12
|
+
class ProviderEnum(Enum):
|
13
|
+
"""Enumeration of supported payment providers."""
|
14
|
+
|
15
|
+
NOWPAYMENTS = "nowpayments"
|
16
|
+
|
17
|
+
@classmethod
|
18
|
+
def get_all_providers(cls) -> List[str]:
|
19
|
+
"""Get list of all provider values."""
|
20
|
+
return [provider.value for provider in cls]
|
21
|
+
|
22
|
+
@classmethod
|
23
|
+
def is_valid_provider(cls, provider_name: str) -> bool:
|
24
|
+
"""Check if provider name is valid."""
|
25
|
+
return provider_name in cls.get_all_providers()
|
26
|
+
|
27
|
+
@classmethod
|
28
|
+
def get_crypto_providers(cls) -> List[str]:
|
29
|
+
"""Get list of crypto-supporting providers."""
|
30
|
+
return [
|
31
|
+
provider.value for provider in cls
|
32
|
+
if PROVIDER_METADATA[provider.value].supports_crypto
|
33
|
+
]
|
34
|
+
|
35
|
+
@classmethod
|
36
|
+
def get_fiat_providers(cls) -> List[str]:
|
37
|
+
"""Get list of fiat-supporting providers."""
|
38
|
+
return [
|
39
|
+
provider.value for provider in cls
|
40
|
+
if PROVIDER_METADATA[provider.value].supports_fiat
|
41
|
+
]
|
42
|
+
|
43
|
+
@classmethod
|
44
|
+
def get_active_providers(cls) -> List[str]:
|
45
|
+
"""Get list of active providers."""
|
46
|
+
return [
|
47
|
+
provider.value for provider in cls
|
48
|
+
if PROVIDER_METADATA[provider.value].status == ProviderStatus.ACTIVE
|
49
|
+
]
|
50
|
+
|
51
|
+
|
52
|
+
# Provider metadata registry
|
53
|
+
PROVIDER_METADATA: Dict[str, ProviderMetadata] = {
|
54
|
+
ProviderEnum.NOWPAYMENTS.value: ProviderMetadata(
|
55
|
+
name="NowPayments",
|
56
|
+
provider_type=ProviderType.CRYPTO,
|
57
|
+
status=ProviderStatus.ACTIVE,
|
58
|
+
priority=10, # High priority
|
59
|
+
|
60
|
+
# Features
|
61
|
+
supports_fiat=False,
|
62
|
+
supports_crypto=True,
|
63
|
+
supports_webhooks=True,
|
64
|
+
supports_refunds=False,
|
65
|
+
supports_partial_payments=False,
|
66
|
+
|
67
|
+
# Limits and fees
|
68
|
+
min_amount_usd=1.0,
|
69
|
+
max_amount_usd=50000.0,
|
70
|
+
fee_percentage=0.5, # 0.5% fee
|
71
|
+
fixed_fee_usd=0.0,
|
72
|
+
|
73
|
+
# Geographic
|
74
|
+
supported_countries=[], # Global support
|
75
|
+
restricted_countries=["US"], # Example restriction
|
76
|
+
requires_kyc=False,
|
77
|
+
|
78
|
+
# Technical
|
79
|
+
api_version="v1",
|
80
|
+
documentation_url="https://documenter.getpostman.com/view/7907941/S1a32n38",
|
81
|
+
status_page_url="https://status.nowpayments.io/",
|
82
|
+
|
83
|
+
# Additional
|
84
|
+
tags=["crypto", "bitcoin", "ethereum", "altcoins", "instant"],
|
85
|
+
description="Cryptocurrency payment processor supporting 300+ cryptocurrencies with instant settlements"
|
86
|
+
)
|
87
|
+
}
|