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,297 +0,0 @@
1
- """
2
- Internal Service Types - ONLY for inter-service communication.
3
-
4
- DO NOT duplicate Django ORM or DRF! Only for:
5
- 1. Providers -> Services (external API response validation)
6
- 2. Service -> Service (internal operations)
7
- 3. Configuration (settings and parameters)
8
- """
9
-
10
- from pydantic import BaseModel, Field, ConfigDict
11
- from decimal import Decimal
12
- from datetime import datetime
13
- from typing import Optional, Dict, Any
14
- from enum import Enum
15
-
16
-
17
- # =============================================================================
18
- # PROVIDERS - External API response validation
19
- # =============================================================================
20
-
21
- class ProviderResponse(BaseModel):
22
- """Validation for any provider response"""
23
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
24
-
25
- success: bool
26
- provider_payment_id: Optional[str] = None
27
- payment_url: Optional[str] = None
28
- pay_amount: Optional[Decimal] = None
29
- pay_currency: Optional[str] = None
30
- pay_address: Optional[str] = None
31
- status: Optional[str] = None
32
- error_message: Optional[str] = None
33
- # Legacy fields for backward compatibility with tests
34
- amount: Optional[Decimal] = None
35
- currency: Optional[str] = None
36
- payment_id: Optional[str] = None
37
- payment_status: Optional[str] = None
38
- currency_code: Optional[str] = None
39
-
40
-
41
- class WebhookData(BaseModel):
42
- """Provider webhook validation"""
43
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
44
-
45
- provider_payment_id: str
46
- status: str
47
- pay_amount: Optional[Decimal] = None
48
- pay_currency: Optional[str] = None
49
- actually_paid: Optional[Decimal] = None
50
- order_id: Optional[str] = None
51
- signature: Optional[str] = None
52
- error_message: Optional[str] = None
53
-
54
-
55
- # =============================================================================
56
- # INTER-SERVICE OPERATIONS - Service-to-service typing
57
- # =============================================================================
58
-
59
- class ServiceOperationResult(BaseModel):
60
- """Result of inter-service operation"""
61
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
62
-
63
- success: bool
64
- error_code: Optional[str] = None
65
- error_message: Optional[str] = None
66
- data: Dict[str, Any] = Field(default_factory=dict)
67
-
68
-
69
- class BalanceUpdateRequest(BaseModel):
70
- """Balance update request between services"""
71
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
72
-
73
- user_id: int = Field(gt=0)
74
- amount: Decimal
75
- source: str
76
- reference_id: Optional[str] = None
77
- metadata: Dict[str, Any] = Field(default_factory=dict)
78
-
79
-
80
- class AccessCheckRequest(BaseModel):
81
- """Access check request between services"""
82
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
83
-
84
- user_id: int = Field(gt=0)
85
- endpoint_group: str
86
- use_cache: bool = True
87
-
88
-
89
- class AccessCheckResult(BaseModel):
90
- """Access check result"""
91
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
92
-
93
- allowed: bool
94
- subscription_id: Optional[str] = None
95
- reason: Optional[str] = None
96
- remaining_requests: Optional[int] = None
97
- usage_percentage: Optional[float] = None
98
-
99
-
100
- # =============================================================================
101
- # CONFIGURATION - Service settings
102
- # =============================================================================
103
-
104
- class RedisConfig(BaseModel):
105
- """Redis configuration"""
106
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
107
-
108
- host: str = "localhost"
109
- port: int = 6379
110
- db: int = 0
111
- password: Optional[str] = None
112
- max_connections: int = 10
113
- timeout_seconds: int = 5
114
-
115
-
116
- class ProviderConfig(BaseModel):
117
- """Base provider configuration"""
118
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
119
-
120
- enabled: bool = True
121
- api_key: str
122
- sandbox: bool = False
123
- timeout_seconds: int = 30
124
- max_retries: int = 3
125
-
126
-
127
- # =============================================================================
128
- # CACHE OPERATIONS - Minimal cache typing
129
- # =============================================================================
130
-
131
- class CacheKey(BaseModel):
132
- """Cache key typing"""
133
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
134
-
135
- key: str
136
- ttl_seconds: Optional[int] = None
137
-
138
-
139
- class RateLimitResult(BaseModel):
140
- """Rate limit check result"""
141
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
142
-
143
- allowed: bool
144
- remaining: int
145
- reset_at: datetime
146
- retry_after_seconds: Optional[int] = None
147
-
148
-
149
- # =============================================================================
150
- # SERVICE RESPONSE MODELS - Typed responses for service methods
151
- # =============================================================================
152
-
153
- class PaymentCreationResult(BaseModel):
154
- """Payment creation response"""
155
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
156
-
157
- success: bool
158
- payment_id: Optional[str] = None
159
- provider_payment_id: Optional[str] = None
160
- payment_url: Optional[str] = None
161
- error: Optional[str] = None
162
-
163
-
164
- class WebhookProcessingResult(BaseModel):
165
- """Webhook processing response"""
166
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
167
-
168
- success: bool
169
- payment_id: Optional[str] = None
170
- status_updated: bool = False
171
- balance_updated: bool = False
172
- error: Optional[str] = None
173
-
174
-
175
- class PaymentStatusResult(BaseModel):
176
- """Payment status response"""
177
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
178
-
179
- payment_id: str
180
- status: str
181
- amount_usd: Decimal
182
- currency_code: str
183
- provider: str
184
- provider_payment_id: Optional[str] = None
185
- created_at: datetime
186
- updated_at: datetime
187
-
188
-
189
- class UserBalanceResult(BaseModel):
190
- """User balance response"""
191
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
192
-
193
- id: str
194
- user_id: int
195
- available_balance: Decimal
196
- total_balance: Decimal
197
- reserved_balance: Decimal
198
- last_updated: datetime
199
- created_at: datetime
200
-
201
-
202
- class TransferResult(BaseModel):
203
- """Funds transfer response"""
204
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
205
-
206
- success: bool
207
- transaction_id: Optional[str] = None
208
- from_user_id: int
209
- to_user_id: int
210
- amount: Decimal
211
- error: Optional[str] = None
212
- error_code: Optional[str] = None
213
-
214
-
215
- class TransactionInfo(BaseModel):
216
- """Transaction information"""
217
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
218
-
219
- id: str
220
- user_id: int
221
- transaction_type: str
222
- amount: Decimal
223
- balance_after: Decimal
224
- source: str
225
- reference_id: Optional[str] = None
226
- description: Optional[str] = None
227
- created_at: datetime
228
-
229
-
230
- class EndpointGroupInfo(BaseModel):
231
- """Endpoint group information"""
232
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
233
-
234
- id: str
235
- name: str
236
- display_name: str
237
-
238
-
239
- class SubscriptionInfo(BaseModel):
240
- """Subscription information"""
241
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
242
-
243
- id: str
244
- endpoint_group: EndpointGroupInfo
245
- status: str
246
- tier: str
247
- monthly_price: Decimal
248
- usage_current: int
249
- usage_limit: int
250
- usage_percentage: float
251
- remaining_requests: int
252
- expires_at: datetime
253
- next_billing: Optional[datetime] = None
254
- created_at: datetime
255
-
256
-
257
- class SubscriptionAnalytics(BaseModel):
258
- """Subscription analytics response"""
259
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
260
-
261
- period: Dict[str, Any] = Field(default_factory=dict)
262
- total_revenue: Decimal
263
- active_subscriptions: int
264
- new_subscriptions: int
265
- churned_subscriptions: int
266
- error: Optional[str] = None
267
-
268
-
269
- # =============================================================================
270
- # ADDITIONAL RESPONSE MODELS - Missing Pydantic models
271
- # =============================================================================
272
-
273
- class PaymentHistoryItem(BaseModel):
274
- """Single payment item for history lists"""
275
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
276
-
277
- id: str
278
- user_id: int
279
- amount: Decimal
280
- currency: str
281
- status: str
282
- provider: str
283
- provider_payment_id: Optional[str] = None
284
- created_at: datetime
285
- updated_at: datetime
286
- metadata: Dict[str, Any] = Field(default_factory=dict)
287
-
288
-
289
- class ProviderInfo(BaseModel):
290
- """Payment provider information"""
291
- model_config = ConfigDict(validate_assignment=True, extra="forbid")
292
-
293
- name: str
294
- display_name: str
295
- supported_currencies: list[str] = Field(default_factory=list)
296
- is_active: bool
297
- features: Dict[str, Any] = Field(default_factory=dict)
@@ -1,8 +0,0 @@
1
- """
2
- Service layer middleware for payments.
3
-
4
- TODO: Implement service middleware when needed.
5
- """
6
-
7
- # Placeholder for future service middleware
8
- __all__ = []
@@ -1,22 +0,0 @@
1
- """
2
- Payment system monitoring services.
3
-
4
- Provides health monitoring, alerting, and fallback mechanisms
5
- for payment providers and system components.
6
- """
7
-
8
- from .provider_health import (
9
- ProviderHealthMonitor,
10
- ProviderHealthCheck,
11
- ProviderHealthSummary,
12
- HealthStatus,
13
- get_health_monitor
14
- )
15
-
16
- __all__ = [
17
- 'ProviderHealthMonitor',
18
- 'ProviderHealthCheck',
19
- 'ProviderHealthSummary',
20
- 'HealthStatus',
21
- 'get_health_monitor'
22
- ]
@@ -1,222 +0,0 @@
1
- """
2
- Pydantic schemas for provider API responses.
3
-
4
- Type-safe models for validating and parsing responses
5
- from payment provider health check endpoints.
6
- """
7
-
8
- from typing import Dict, Optional, Any
9
- from decimal import Decimal
10
- from datetime import datetime
11
- from pydantic import BaseModel, Field, validator
12
-
13
-
14
- class CryptAPIInfoResponse(BaseModel):
15
- """CryptAPI /btc/info/ response schema."""
16
-
17
- coin: str = Field(..., description="Cryptocurrency name")
18
- logo: str = Field(..., description="Logo URL")
19
- ticker: str = Field(..., description="Currency ticker")
20
- minimum_transaction: int = Field(..., description="Minimum transaction in satoshis")
21
- minimum_transaction_coin: str = Field(..., description="Minimum transaction in coin units")
22
- minimum_fee: int = Field(..., description="Minimum fee in satoshis")
23
- minimum_fee_coin: str = Field(..., description="Minimum fee in coin units")
24
- fee_percent: str = Field(..., description="Fee percentage")
25
- network_fee_estimation: str = Field(..., description="Network fee estimation")
26
- status: str = Field(..., description="API status")
27
- prices: Dict[str, str] = Field(..., description="Prices in various fiat currencies")
28
- prices_updated: str = Field(..., description="Prices last updated timestamp")
29
-
30
- @validator('status')
31
- def validate_status(cls, v):
32
- """Validate that status is success."""
33
- if v != 'success':
34
- raise ValueError(f"Expected status 'success', got '{v}'")
35
- return v
36
-
37
- @validator('prices')
38
- def validate_prices_not_empty(cls, v):
39
- """Validate that prices dict is not empty."""
40
- if not v:
41
- raise ValueError("Prices dictionary cannot be empty")
42
- return v
43
-
44
- def get_usd_price(self) -> Optional[Decimal]:
45
- """Get USD price as Decimal."""
46
- usd_price = self.prices.get('USD')
47
- if usd_price:
48
- try:
49
- return Decimal(usd_price)
50
- except:
51
- return None
52
- return None
53
-
54
-
55
- class NowPaymentsStatusResponse(BaseModel):
56
- """NowPayments /v1/status response schema."""
57
-
58
- message: str = Field(..., description="Status message")
59
-
60
- @validator('message')
61
- def validate_message_ok(cls, v):
62
- """Validate that message is OK."""
63
- if v.upper() != 'OK':
64
- raise ValueError(f"Expected message 'OK', got '{v}'")
65
- return v
66
-
67
-
68
- class StripeErrorResponse(BaseModel):
69
- """Stripe API error response schema."""
70
-
71
- class StripeError(BaseModel):
72
- message: str = Field(..., description="Error message")
73
- type: str = Field(..., description="Error type")
74
-
75
- error: StripeError = Field(..., description="Error details")
76
-
77
- @validator('error')
78
- def validate_auth_error(cls, v):
79
- """Validate this is an authentication error (meaning API is healthy)."""
80
- if v.type != 'invalid_request_error':
81
- raise ValueError(f"Expected auth error, got '{v.type}'")
82
- return v
83
-
84
-
85
- class CryptomusErrorResponse(BaseModel):
86
- """Cryptomus API error response schema."""
87
-
88
- error: str = Field(..., description="Error message")
89
-
90
- @validator('error')
91
- def validate_not_found_error(cls, v):
92
- """Validate this is a not found error (meaning API is responding)."""
93
- if v.lower() not in ['not found', 'unauthorized', 'forbidden']:
94
- raise ValueError(f"Unexpected error: {v}")
95
- return v
96
-
97
-
98
- class GenericAPIHealthResponse(BaseModel):
99
- """Generic API health response for unknown formats."""
100
-
101
- status_code: int = Field(..., description="HTTP status code")
102
- response_body: str = Field(..., description="Raw response body")
103
- response_time_ms: float = Field(..., description="Response time in milliseconds")
104
-
105
- def is_healthy(self) -> bool:
106
- """Determine if API is healthy based on status code."""
107
- # 2xx = healthy, 401/403 = healthy (auth required), 4xx = degraded, 5xx = unhealthy
108
- if 200 <= self.status_code < 300:
109
- return True
110
- elif self.status_code in [401, 403]:
111
- return True # Auth required but API responding
112
- else:
113
- return False
114
-
115
-
116
- class ProviderHealthResponse(BaseModel):
117
- """Unified health response model for all providers."""
118
-
119
- provider_name: str = Field(..., description="Provider name")
120
- is_healthy: bool = Field(..., description="Is provider healthy")
121
- status_code: int = Field(..., description="HTTP status code")
122
- response_time_ms: float = Field(..., description="Response time in milliseconds")
123
- error_message: Optional[str] = Field(None, description="Error message if unhealthy")
124
- parsed_response: Optional[Dict[str, Any]] = Field(None, description="Parsed API response")
125
- raw_response: Optional[str] = Field(None, description="Raw response body")
126
- checked_at: datetime = Field(default_factory=datetime.now, description="Check timestamp")
127
-
128
- class Config:
129
- json_encoders = {
130
- datetime: lambda v: v.isoformat()
131
- }
132
-
133
-
134
- def parse_provider_response(provider_name: str, status_code: int, response_body: str, response_time_ms: float) -> ProviderHealthResponse:
135
- """
136
- Parse provider API response using appropriate schema.
137
-
138
- Args:
139
- provider_name: Name of the provider
140
- status_code: HTTP status code
141
- response_body: Raw response body
142
- response_time_ms: Response time in milliseconds
143
-
144
- Returns:
145
- ProviderHealthResponse with parsed data
146
- """
147
- parsed_response = None
148
- error_message = None
149
- is_healthy = False
150
-
151
- try:
152
- import json
153
- response_json = json.loads(response_body) if response_body else {}
154
-
155
- if provider_name == 'cryptapi':
156
- if status_code == 200:
157
- cryptapi_response = CryptAPIInfoResponse(**response_json)
158
- parsed_response = cryptapi_response.dict()
159
- is_healthy = True
160
- else:
161
- error_message = f"CryptAPI returned status {status_code}"
162
-
163
- elif provider_name == 'nowpayments':
164
- if status_code == 200:
165
- nowpayments_response = NowPaymentsStatusResponse(**response_json)
166
- parsed_response = nowpayments_response.dict()
167
- is_healthy = True
168
- else:
169
- error_message = f"NowPayments returned status {status_code}"
170
-
171
- elif provider_name == 'stripe':
172
- if status_code == 401:
173
- stripe_response = StripeErrorResponse(**response_json)
174
- parsed_response = stripe_response.dict()
175
- is_healthy = True # Auth error = API responding
176
- elif 200 <= status_code < 300:
177
- parsed_response = response_json
178
- is_healthy = True
179
- else:
180
- error_message = f"Stripe returned unexpected status {status_code}"
181
-
182
- elif provider_name == 'cryptomus':
183
- if status_code == 404 and response_json.get('error') == 'Not found':
184
- cryptomus_response = CryptomusErrorResponse(**response_json)
185
- parsed_response = cryptomus_response.dict()
186
- is_healthy = True # Not found = API responding
187
- elif status_code == 204:
188
- # No Content = API responding and healthy
189
- parsed_response = {'status': 'no_content', 'message': 'API responding correctly'}
190
- is_healthy = True
191
- elif status_code in [401, 403]:
192
- is_healthy = True # Auth required = API responding
193
- parsed_response = response_json
194
- elif 200 <= status_code < 300:
195
- parsed_response = response_json
196
- is_healthy = True
197
- else:
198
- error_message = f"Cryptomus returned status {status_code}"
199
-
200
- else:
201
- # Generic handling for unknown providers
202
- generic_response = GenericAPIHealthResponse(
203
- status_code=status_code,
204
- response_body=response_body,
205
- response_time_ms=response_time_ms
206
- )
207
- parsed_response = generic_response.dict()
208
- is_healthy = generic_response.is_healthy()
209
-
210
- except Exception as e:
211
- error_message = f"Failed to parse {provider_name} response: {str(e)}"
212
- is_healthy = False
213
-
214
- return ProviderHealthResponse(
215
- provider_name=provider_name,
216
- is_healthy=is_healthy,
217
- status_code=status_code,
218
- response_time_ms=response_time_ms,
219
- error_message=error_message,
220
- parsed_response=parsed_response,
221
- raw_response=response_body
222
- )