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.
Files changed (258) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/api/health/views.py +4 -2
  3. django_cfg/apps/knowbase/config/settings.py +16 -15
  4. django_cfg/apps/payments/README.md +326 -0
  5. django_cfg/apps/payments/admin/__init__.py +20 -9
  6. django_cfg/apps/payments/admin/api_keys_admin.py +521 -237
  7. django_cfg/apps/payments/admin/balance_admin.py +592 -297
  8. django_cfg/apps/payments/admin/currencies_admin.py +600 -108
  9. django_cfg/apps/payments/admin/filters.py +306 -199
  10. django_cfg/apps/payments/admin/payments_admin.py +470 -64
  11. django_cfg/apps/payments/admin/subscriptions_admin.py +578 -128
  12. django_cfg/apps/payments/admin_interface/__init__.py +18 -0
  13. django_cfg/apps/payments/admin_interface/templates/payments/base.html +162 -0
  14. django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +38 -0
  15. django_cfg/apps/payments/admin_interface/templates/payments/components/loading_spinner.html +16 -0
  16. django_cfg/apps/payments/admin_interface/templates/payments/components/notification.html +27 -0
  17. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_card.html +86 -0
  18. django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +39 -0
  19. django_cfg/apps/payments/admin_interface/templates/payments/currency_converter.html +382 -0
  20. django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +300 -0
  21. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +303 -0
  22. django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +382 -0
  23. django_cfg/apps/payments/admin_interface/templates/payments/payment_status.html +500 -0
  24. django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +594 -0
  25. django_cfg/apps/payments/admin_interface/views/__init__.py +23 -0
  26. django_cfg/apps/payments/admin_interface/views/payment_views.py +259 -0
  27. django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +37 -0
  28. django_cfg/apps/payments/apps.py +34 -9
  29. django_cfg/apps/payments/config/__init__.py +28 -51
  30. django_cfg/apps/payments/config/constance/__init__.py +22 -0
  31. django_cfg/apps/payments/config/constance/config_service.py +123 -0
  32. django_cfg/apps/payments/config/constance/fields.py +69 -0
  33. django_cfg/apps/payments/config/constance/settings.py +160 -0
  34. django_cfg/apps/payments/config/django_cfg_integration.py +202 -0
  35. django_cfg/apps/payments/config/helpers.py +130 -0
  36. django_cfg/apps/payments/management/__init__.py +1 -3
  37. django_cfg/apps/payments/management/commands/__init__.py +1 -3
  38. django_cfg/apps/payments/management/commands/manage_currencies.py +381 -0
  39. django_cfg/apps/payments/management/commands/manage_providers.py +408 -0
  40. django_cfg/apps/payments/middleware/__init__.py +3 -1
  41. django_cfg/apps/payments/middleware/api_access.py +329 -222
  42. django_cfg/apps/payments/middleware/rate_limiting.py +343 -163
  43. django_cfg/apps/payments/middleware/usage_tracking.py +250 -238
  44. django_cfg/apps/payments/migrations/0001_initial.py +708 -536
  45. django_cfg/apps/payments/models/__init__.py +16 -20
  46. django_cfg/apps/payments/models/api_keys.py +121 -43
  47. django_cfg/apps/payments/models/balance.py +150 -115
  48. django_cfg/apps/payments/models/base.py +68 -15
  49. django_cfg/apps/payments/models/currencies.py +207 -67
  50. django_cfg/apps/payments/models/managers/__init__.py +44 -0
  51. django_cfg/apps/payments/models/managers/api_key_managers.py +329 -0
  52. django_cfg/apps/payments/models/managers/balance_managers.py +599 -0
  53. django_cfg/apps/payments/models/managers/currency_managers.py +385 -0
  54. django_cfg/apps/payments/models/managers/payment_managers.py +511 -0
  55. django_cfg/apps/payments/models/managers/subscription_managers.py +641 -0
  56. django_cfg/apps/payments/models/payments.py +235 -284
  57. django_cfg/apps/payments/models/subscriptions.py +257 -177
  58. django_cfg/apps/payments/models/tariffs.py +147 -40
  59. django_cfg/apps/payments/services/__init__.py +209 -56
  60. django_cfg/apps/payments/services/cache/__init__.py +6 -6
  61. django_cfg/apps/payments/services/cache/{simple_cache.py → cache_service.py} +112 -12
  62. django_cfg/apps/payments/services/core/__init__.py +10 -6
  63. django_cfg/apps/payments/services/core/balance_service.py +435 -360
  64. django_cfg/apps/payments/services/core/base.py +166 -0
  65. django_cfg/apps/payments/services/core/currency_service.py +478 -0
  66. django_cfg/apps/payments/services/core/payment_service.py +344 -468
  67. django_cfg/apps/payments/services/core/subscription_service.py +425 -484
  68. django_cfg/apps/payments/services/core/webhook_service.py +410 -0
  69. django_cfg/apps/payments/services/integrations/__init__.py +29 -0
  70. django_cfg/apps/payments/services/integrations/ngrok_service.py +47 -0
  71. django_cfg/apps/payments/services/integrations/providers_config.py +107 -0
  72. django_cfg/apps/payments/services/providers/__init__.py +9 -14
  73. django_cfg/apps/payments/services/providers/base.py +232 -71
  74. django_cfg/apps/payments/services/providers/nowpayments.py +404 -219
  75. django_cfg/apps/payments/services/providers/registry.py +429 -80
  76. django_cfg/apps/payments/services/types/__init__.py +78 -0
  77. django_cfg/apps/payments/services/types/data.py +177 -0
  78. django_cfg/apps/payments/services/types/requests.py +150 -0
  79. django_cfg/apps/payments/services/types/responses.py +156 -0
  80. django_cfg/apps/payments/services/types/webhooks.py +232 -0
  81. django_cfg/apps/payments/signals/__init__.py +33 -8
  82. django_cfg/apps/payments/signals/api_key_signals.py +211 -130
  83. django_cfg/apps/payments/signals/balance_signals.py +174 -0
  84. django_cfg/apps/payments/signals/payment_signals.py +129 -98
  85. django_cfg/apps/payments/signals/subscription_signals.py +195 -143
  86. django_cfg/apps/payments/static/payments/css/components.css +380 -0
  87. django_cfg/apps/payments/static/payments/css/dashboard.css +188 -0
  88. django_cfg/apps/payments/static/payments/js/components.js +545 -0
  89. django_cfg/apps/payments/static/payments/js/utils.js +412 -0
  90. django_cfg/apps/payments/templatetags/__init__.py +1 -1
  91. django_cfg/apps/payments/templatetags/payment_tags.py +466 -0
  92. django_cfg/apps/payments/urls.py +46 -47
  93. django_cfg/apps/payments/urls_admin.py +49 -0
  94. django_cfg/apps/payments/views/api/__init__.py +101 -0
  95. django_cfg/apps/payments/views/api/api_keys.py +387 -0
  96. django_cfg/apps/payments/views/api/balances.py +381 -0
  97. django_cfg/apps/payments/views/api/base.py +298 -0
  98. django_cfg/apps/payments/views/api/currencies.py +402 -0
  99. django_cfg/apps/payments/views/api/payments.py +415 -0
  100. django_cfg/apps/payments/views/api/subscriptions.py +475 -0
  101. django_cfg/apps/payments/views/api/webhooks.py +476 -0
  102. django_cfg/apps/payments/views/serializers/__init__.py +99 -0
  103. django_cfg/apps/payments/views/serializers/api_keys.py +424 -0
  104. django_cfg/apps/payments/views/serializers/balances.py +300 -0
  105. django_cfg/apps/payments/views/serializers/currencies.py +335 -0
  106. django_cfg/apps/payments/views/serializers/payments.py +387 -0
  107. django_cfg/apps/payments/views/serializers/subscriptions.py +429 -0
  108. django_cfg/apps/payments/views/serializers/webhooks.py +137 -0
  109. django_cfg/apps/tasks/urls.py +0 -2
  110. django_cfg/apps/tasks/urls_admin.py +14 -0
  111. django_cfg/apps/urls.py +4 -4
  112. django_cfg/config.py +1 -1
  113. django_cfg/core/config.py +75 -4
  114. django_cfg/core/generation.py +25 -4
  115. django_cfg/core/integration/README.md +363 -0
  116. django_cfg/core/integration/__init__.py +47 -0
  117. django_cfg/core/integration/commands_collector.py +239 -0
  118. django_cfg/core/integration/display/__init__.py +15 -0
  119. django_cfg/core/integration/display/base.py +157 -0
  120. django_cfg/core/integration/display/ngrok.py +164 -0
  121. django_cfg/core/integration/display/startup.py +815 -0
  122. django_cfg/core/integration/url_integration.py +123 -0
  123. django_cfg/core/integration/version_checker.py +160 -0
  124. django_cfg/management/commands/auto_generate.py +4 -0
  125. django_cfg/management/commands/check_settings.py +6 -0
  126. django_cfg/management/commands/clear_constance.py +5 -2
  127. django_cfg/management/commands/create_token.py +6 -0
  128. django_cfg/management/commands/list_urls.py +6 -0
  129. django_cfg/management/commands/migrate_all.py +6 -0
  130. django_cfg/management/commands/migrator.py +3 -0
  131. django_cfg/management/commands/rundramatiq.py +6 -0
  132. django_cfg/management/commands/runserver_ngrok.py +51 -29
  133. django_cfg/management/commands/script.py +6 -0
  134. django_cfg/management/commands/show_config.py +12 -2
  135. django_cfg/management/commands/show_urls.py +4 -0
  136. django_cfg/management/commands/superuser.py +6 -0
  137. django_cfg/management/commands/task_clear.py +4 -1
  138. django_cfg/management/commands/task_status.py +3 -1
  139. django_cfg/management/commands/test_email.py +3 -0
  140. django_cfg/management/commands/test_telegram.py +6 -0
  141. django_cfg/management/commands/test_twilio.py +6 -0
  142. django_cfg/management/commands/tree.py +6 -0
  143. django_cfg/management/commands/validate_config.py +155 -149
  144. django_cfg/models/constance.py +31 -11
  145. django_cfg/models/payments.py +175 -498
  146. django_cfg/modules/django_currency/__init__.py +16 -11
  147. django_cfg/modules/django_currency/clients/__init__.py +4 -4
  148. django_cfg/modules/django_currency/clients/coinpaprika_client.py +289 -0
  149. django_cfg/modules/django_currency/clients/yahoo_client.py +157 -0
  150. django_cfg/modules/django_currency/core/__init__.py +1 -7
  151. django_cfg/modules/django_currency/core/converter.py +18 -23
  152. django_cfg/modules/django_currency/core/models.py +122 -11
  153. django_cfg/modules/django_currency/database/__init__.py +4 -4
  154. django_cfg/modules/django_currency/database/database_loader.py +190 -309
  155. django_cfg/modules/django_logger.py +160 -146
  156. django_cfg/modules/django_unfold/dashboard.py +65 -12
  157. django_cfg/registry/core.py +1 -0
  158. django_cfg/template_archive/django_sample.zip +0 -0
  159. django_cfg/templates/admin/components/action_grid.html +9 -9
  160. django_cfg/templates/admin/components/metric_card.html +5 -5
  161. django_cfg/templates/admin/components/status_badge.html +2 -2
  162. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +152 -24
  163. django_cfg/templates/admin/snippets/components/quick_actions.html +3 -3
  164. django_cfg/templates/admin/snippets/components/system_health.html +1 -1
  165. django_cfg/templates/admin/snippets/tabs/overview_tab.html +49 -52
  166. django_cfg/utils/smart_defaults.py +222 -571
  167. django_cfg/utils/toolkit.py +51 -11
  168. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/METADATA +5 -4
  169. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/RECORD +172 -182
  170. django_cfg/apps/payments/__init__.py +0 -8
  171. django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
  172. django_cfg/apps/payments/config/module.py +0 -70
  173. django_cfg/apps/payments/config/providers.py +0 -105
  174. django_cfg/apps/payments/config/settings.py +0 -96
  175. django_cfg/apps/payments/config/utils.py +0 -52
  176. django_cfg/apps/payments/decorators.py +0 -291
  177. django_cfg/apps/payments/management/commands/README.md +0 -178
  178. django_cfg/apps/payments/management/commands/currency_stats.py +0 -323
  179. django_cfg/apps/payments/management/commands/populate_currencies.py +0 -246
  180. django_cfg/apps/payments/management/commands/update_currencies.py +0 -336
  181. django_cfg/apps/payments/managers/__init__.py +0 -22
  182. django_cfg/apps/payments/managers/api_key_manager.py +0 -35
  183. django_cfg/apps/payments/managers/balance_manager.py +0 -361
  184. django_cfg/apps/payments/managers/currency_manager.py +0 -83
  185. django_cfg/apps/payments/managers/payment_manager.py +0 -44
  186. django_cfg/apps/payments/managers/subscription_manager.py +0 -37
  187. django_cfg/apps/payments/managers/tariff_manager.py +0 -29
  188. django_cfg/apps/payments/models/events.py +0 -73
  189. django_cfg/apps/payments/serializers/__init__.py +0 -56
  190. django_cfg/apps/payments/serializers/api_keys.py +0 -51
  191. django_cfg/apps/payments/serializers/balance.py +0 -59
  192. django_cfg/apps/payments/serializers/currencies.py +0 -55
  193. django_cfg/apps/payments/serializers/payments.py +0 -62
  194. django_cfg/apps/payments/serializers/subscriptions.py +0 -71
  195. django_cfg/apps/payments/serializers/tariffs.py +0 -56
  196. django_cfg/apps/payments/services/billing/__init__.py +0 -8
  197. django_cfg/apps/payments/services/cache/base.py +0 -30
  198. django_cfg/apps/payments/services/core/fallback_service.py +0 -432
  199. django_cfg/apps/payments/services/internal_types.py +0 -297
  200. django_cfg/apps/payments/services/middleware/__init__.py +0 -8
  201. django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
  202. django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -222
  203. django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
  204. django_cfg/apps/payments/services/providers/cryptapi.py +0 -273
  205. django_cfg/apps/payments/services/providers/cryptomus.py +0 -311
  206. django_cfg/apps/payments/services/security/__init__.py +0 -34
  207. django_cfg/apps/payments/services/security/error_handler.py +0 -637
  208. django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
  209. django_cfg/apps/payments/services/security/webhook_validator.py +0 -475
  210. django_cfg/apps/payments/services/validators/__init__.py +0 -8
  211. django_cfg/apps/payments/static/payments/css/payments.css +0 -340
  212. django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
  213. django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
  214. django_cfg/apps/payments/static/payments/js/theme.js +0 -86
  215. django_cfg/apps/payments/tasks/__init__.py +0 -12
  216. django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
  217. django_cfg/apps/payments/templates/payments/base.html +0 -182
  218. django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
  219. django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
  220. django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -36
  221. django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
  222. django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -27
  223. django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -144
  224. django_cfg/apps/payments/templates/payments/dashboard.html +0 -346
  225. django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
  226. django_cfg/apps/payments/urls_templates.py +0 -52
  227. django_cfg/apps/payments/utils/__init__.py +0 -45
  228. django_cfg/apps/payments/utils/billing_utils.py +0 -342
  229. django_cfg/apps/payments/utils/config_utils.py +0 -245
  230. django_cfg/apps/payments/utils/middleware_utils.py +0 -228
  231. django_cfg/apps/payments/utils/validation_utils.py +0 -94
  232. django_cfg/apps/payments/views/__init__.py +0 -62
  233. django_cfg/apps/payments/views/api_key_views.py +0 -164
  234. django_cfg/apps/payments/views/balance_views.py +0 -75
  235. django_cfg/apps/payments/views/currency_views.py +0 -111
  236. django_cfg/apps/payments/views/payment_views.py +0 -149
  237. django_cfg/apps/payments/views/subscription_views.py +0 -135
  238. django_cfg/apps/payments/views/tariff_views.py +0 -131
  239. django_cfg/apps/payments/views/templates/__init__.py +0 -25
  240. django_cfg/apps/payments/views/templates/ajax.py +0 -312
  241. django_cfg/apps/payments/views/templates/base.py +0 -204
  242. django_cfg/apps/payments/views/templates/dashboard.py +0 -60
  243. django_cfg/apps/payments/views/templates/payment_detail.py +0 -102
  244. django_cfg/apps/payments/views/templates/payment_management.py +0 -164
  245. django_cfg/apps/payments/views/templates/qr_code.py +0 -174
  246. django_cfg/apps/payments/views/templates/stats.py +0 -240
  247. django_cfg/apps/payments/views/templates/utils.py +0 -181
  248. django_cfg/apps/payments/views/webhook_views.py +0 -266
  249. django_cfg/apps/payments/viewsets.py +0 -65
  250. django_cfg/core/integration.py +0 -160
  251. django_cfg/modules/django_currency/clients/coingecko_client.py +0 -257
  252. django_cfg/modules/django_currency/clients/yfinance_client.py +0 -246
  253. django_cfg/template_archive/.gitignore +0 -1
  254. django_cfg/template_archive/__init__.py +0 -0
  255. django_cfg/urls.py +0 -33
  256. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
  257. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
  258. {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 payment provider interface.
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
- from ..internal_types import ProviderResponse, WebhookData
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 PaymentProvider(ABC):
15
- """Abstract base class for payment providers."""
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: dict):
18
- """Initialize provider with config."""
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.name = self.__class__.__name__.lower().replace('provider', '')
21
- self.enabled = config.get('enabled', True)
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, payment_data: dict) -> ProviderResponse:
81
+ def create_payment(self, request: PaymentRequest) -> ProviderResponse:
25
82
  """
26
- Create a payment request.
83
+ Create payment with provider.
27
84
 
28
85
  Args:
29
- amount: Payment amount
30
- currency: Payment currency
31
- **kwargs: Additional parameters (order_id, description, etc.)
86
+ request: Payment creation request
32
87
 
33
88
  Returns:
34
- Dict with payment creation result
89
+ ProviderResponse: Provider response with payment details
35
90
  """
36
91
  pass
37
92
 
38
93
  @abstractmethod
39
- def check_payment_status(self, payment_id: str) -> ProviderResponse:
94
+ def get_payment_status(self, provider_payment_id: str) -> ProviderResponse:
40
95
  """
41
- Check payment status.
96
+ Get payment status from provider.
42
97
 
43
98
  Args:
44
- payment_id: Payment ID from provider
99
+ provider_payment_id: Provider's payment ID
45
100
 
46
101
  Returns:
47
- Dict with payment status
102
+ ProviderResponse: Current payment status
48
103
  """
49
104
  pass
50
105
 
51
106
  @abstractmethod
52
- def process_webhook(self, payload: dict) -> WebhookData:
107
+ def get_supported_currencies(self) -> ServiceOperationResult:
53
108
  """
54
- Process webhook payload.
109
+ Get list of supported currencies from provider.
55
110
 
56
- Args:
57
- payload: Webhook data from provider
58
-
59
111
  Returns:
60
- Dict with processed webhook data
112
+ ServiceOperationResult: List of supported currencies
61
113
  """
62
114
  pass
63
115
 
64
116
  @abstractmethod
65
- def get_supported_currencies(self) -> List[str]:
117
+ def validate_webhook(self, payload: Dict[str, Any], signature: str = None) -> ServiceOperationResult:
66
118
  """
67
- Get list of supported currencies.
119
+ Validate webhook from provider.
68
120
 
121
+ Args:
122
+ payload: Webhook payload
123
+ signature: Webhook signature (if any)
124
+
69
125
  Returns:
70
- List of supported currency codes
126
+ ServiceOperationResult: Validation result
71
127
  """
72
128
  pass
73
129
 
74
- def validate_webhook(self, payload: dict, headers: Optional[dict] = None) -> bool:
130
+ def get_exchange_rate(self, from_currency: str, to_currency: str) -> ServiceOperationResult:
75
131
  """
76
- Validate webhook signature and data.
132
+ Get exchange rate from provider (optional).
77
133
 
78
134
  Args:
79
- payload: Webhook data
80
- signature: Webhook signature (if applicable)
135
+ from_currency: Source currency
136
+ to_currency: Target currency
81
137
 
82
138
  Returns:
83
- True if webhook is valid
139
+ ServiceOperationResult: Exchange rate or not supported
84
140
  """
85
- # Default implementation - providers can override
86
- return True
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 get_minimum_payment_amount(self, currency_from: str, currency_to: str = 'usd') -> Optional[Decimal]:
147
+ def health_check(self) -> ServiceOperationResult:
89
148
  """
90
- Get minimum payment amount for currency pair.
149
+ Perform provider health check.
91
150
 
92
- Args:
93
- currency_from: Source currency
94
- currency_to: Target currency
95
-
96
151
  Returns:
97
- Minimum payment amount or None if not supported
152
+ ServiceOperationResult: Health check result
98
153
  """
99
- # Optional method - providers can override
100
- return None
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 estimate_payment_amount(self, amount: Decimal, currency_code: str) -> Optional[dict]:
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
- Estimate payment amount in target currency.
194
+ Make HTTP request to provider API.
105
195
 
106
196
  Args:
107
- amount: Amount to estimate
108
- currency_code: Target currency
197
+ method: HTTP method
198
+ endpoint: API endpoint
199
+ data: Request data
200
+ headers: Request headers
109
201
 
110
202
  Returns:
111
- Dict with estimation data or None if not supported
203
+ Dict[str, Any]: Response data
204
+
205
+ Raises:
206
+ Exception: If request fails
112
207
  """
113
- # Optional method - providers can override
114
- return None
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 check_api_status(self) -> bool:
268
+ def _create_provider_response(
269
+ self,
270
+ success: bool,
271
+ raw_response: Dict[str, Any],
272
+ **kwargs
273
+ ) -> ProviderResponse:
117
274
  """
118
- Check if provider API is available.
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
- True if API is available
122
- """
123
- # Optional method - providers can override
124
- return True
125
-
126
- def is_enabled(self) -> bool:
127
- """Check if provider is enabled."""
128
- return self.enabled
129
-
130
- def get_provider_info(self) -> dict:
131
- """Get provider information."""
132
- return {
133
- 'name': self.name,
134
- 'enabled': self.enabled,
135
- 'supported_currencies': self.get_supported_currencies(),
136
- 'api_status': self.check_api_status(),
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}')"