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.
Files changed (246) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/__init__.py +24 -8
  3. django_cfg/apps/accounts/admin/activity_admin.py +146 -0
  4. django_cfg/apps/accounts/admin/filters.py +98 -22
  5. django_cfg/apps/accounts/admin/group_admin.py +86 -0
  6. django_cfg/apps/accounts/admin/inlines.py +42 -13
  7. django_cfg/apps/accounts/admin/otp_admin.py +115 -0
  8. django_cfg/apps/accounts/admin/registration_admin.py +173 -0
  9. django_cfg/apps/accounts/admin/resources.py +123 -19
  10. django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
  11. django_cfg/apps/accounts/admin/user_admin.py +362 -0
  12. django_cfg/apps/agents/admin/__init__.py +17 -4
  13. django_cfg/apps/agents/admin/execution_admin.py +204 -183
  14. django_cfg/apps/agents/admin/registry_admin.py +230 -255
  15. django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
  16. django_cfg/apps/agents/core/__init__.py +1 -1
  17. django_cfg/apps/agents/core/django_agent.py +221 -0
  18. django_cfg/apps/agents/core/exceptions.py +14 -0
  19. django_cfg/apps/agents/core/orchestrator.py +18 -3
  20. django_cfg/apps/knowbase/admin/__init__.py +1 -1
  21. django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
  22. django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
  23. django_cfg/apps/knowbase/admin/document_admin.py +269 -262
  24. django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
  25. django_cfg/apps/knowbase/config/settings.py +21 -4
  26. django_cfg/apps/knowbase/views/chat_views.py +3 -0
  27. django_cfg/apps/leads/admin/__init__.py +3 -1
  28. django_cfg/apps/leads/admin/leads_admin.py +235 -35
  29. django_cfg/apps/maintenance/admin/__init__.py +2 -2
  30. django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
  31. django_cfg/apps/maintenance/admin/log_admin.py +143 -61
  32. django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
  33. django_cfg/apps/maintenance/admin/site_admin.py +213 -352
  34. django_cfg/apps/newsletter/admin/__init__.py +29 -2
  35. django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
  36. django_cfg/apps/payments/admin/__init__.py +18 -27
  37. django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
  38. django_cfg/apps/payments/admin/balance_admin.py +166 -632
  39. django_cfg/apps/payments/admin/currencies_admin.py +235 -607
  40. django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
  41. django_cfg/apps/payments/admin/filters.py +83 -3
  42. django_cfg/apps/payments/admin/networks_admin.py +269 -0
  43. django_cfg/apps/payments/admin/payments_admin.py +183 -460
  44. django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
  45. django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
  46. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
  47. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
  48. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
  49. django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
  50. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
  51. django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
  52. django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
  53. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
  54. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
  55. django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
  56. django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
  57. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
  58. django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
  59. django_cfg/apps/payments/config/__init__.py +14 -15
  60. django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
  61. django_cfg/apps/payments/config/helpers.py +8 -13
  62. django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
  63. django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
  64. django_cfg/apps/payments/middleware/api_access.py +32 -6
  65. django_cfg/apps/payments/migrations/0001_initial.py +33 -46
  66. django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
  67. django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
  68. django_cfg/apps/payments/models/balance.py +12 -0
  69. django_cfg/apps/payments/models/currencies.py +106 -32
  70. django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
  71. django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
  72. django_cfg/apps/payments/models/payments.py +94 -0
  73. django_cfg/apps/payments/services/core/base.py +4 -4
  74. django_cfg/apps/payments/services/core/currency_service.py +35 -28
  75. django_cfg/apps/payments/services/core/payment_service.py +266 -39
  76. django_cfg/apps/payments/services/providers/__init__.py +3 -0
  77. django_cfg/apps/payments/services/providers/base.py +303 -41
  78. django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
  79. django_cfg/apps/payments/services/providers/models/base.py +145 -0
  80. django_cfg/apps/payments/services/providers/models/providers.py +87 -0
  81. django_cfg/apps/payments/services/providers/models/universal.py +48 -0
  82. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
  83. django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
  84. django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
  85. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
  86. django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
  87. django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
  88. django_cfg/apps/payments/services/providers/registry.py +9 -37
  89. django_cfg/apps/payments/services/providers/sync_service.py +277 -0
  90. django_cfg/apps/payments/services/types/requests.py +19 -7
  91. django_cfg/apps/payments/signals/payment_signals.py +31 -2
  92. django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
  93. django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
  94. django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
  95. django_cfg/apps/payments/tasks/__init__.py +39 -0
  96. django_cfg/apps/payments/tasks/types.py +73 -0
  97. django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
  98. django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
  99. django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
  100. django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
  101. django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
  102. django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
  103. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
  104. django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
  105. django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
  106. django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
  107. django_cfg/apps/payments/urls.py +3 -2
  108. django_cfg/apps/payments/urls_admin.py +1 -1
  109. django_cfg/apps/payments/views/api/currencies.py +8 -5
  110. django_cfg/apps/payments/views/overview/services.py +2 -2
  111. django_cfg/apps/payments/views/serializers/currencies.py +22 -8
  112. django_cfg/apps/support/admin/__init__.py +10 -1
  113. django_cfg/apps/support/admin/support_admin.py +338 -141
  114. django_cfg/apps/tasks/admin/__init__.py +11 -0
  115. django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
  116. django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
  117. django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
  118. django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
  119. django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
  120. django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
  121. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
  122. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
  123. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
  124. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
  125. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
  126. django_cfg/apps/tasks/tasks/__init__.py +10 -0
  127. django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
  128. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
  129. django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
  130. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
  131. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
  132. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
  133. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
  134. django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
  135. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
  136. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
  137. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
  138. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
  139. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
  140. django_cfg/apps/tasks/urls.py +2 -2
  141. django_cfg/apps/tasks/urls_admin.py +2 -2
  142. django_cfg/apps/tasks/utils/__init__.py +1 -0
  143. django_cfg/apps/tasks/utils/simulator.py +356 -0
  144. django_cfg/apps/tasks/views/__init__.py +16 -0
  145. django_cfg/apps/tasks/views/api.py +569 -0
  146. django_cfg/apps/tasks/views/dashboard.py +58 -0
  147. django_cfg/config.py +1 -1
  148. django_cfg/core/config.py +10 -5
  149. django_cfg/core/generation.py +1 -1
  150. django_cfg/core/integration/__init__.py +21 -0
  151. django_cfg/management/commands/__init__.py +13 -1
  152. django_cfg/management/commands/migrate_all.py +9 -3
  153. django_cfg/management/commands/migrator.py +11 -6
  154. django_cfg/management/commands/rundramatiq.py +3 -2
  155. django_cfg/management/commands/rundramatiq_simulator.py +430 -0
  156. django_cfg/middleware/__init__.py +0 -2
  157. django_cfg/models/api_keys.py +115 -0
  158. django_cfg/models/constance.py +0 -11
  159. django_cfg/models/payments.py +137 -3
  160. django_cfg/modules/django_admin/__init__.py +64 -0
  161. django_cfg/modules/django_admin/decorators/__init__.py +13 -0
  162. django_cfg/modules/django_admin/decorators/actions.py +106 -0
  163. django_cfg/modules/django_admin/decorators/display.py +106 -0
  164. django_cfg/modules/django_admin/mixins/__init__.py +14 -0
  165. django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
  166. django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
  167. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
  168. django_cfg/modules/django_admin/models/__init__.py +20 -0
  169. django_cfg/modules/django_admin/models/action_models.py +33 -0
  170. django_cfg/modules/django_admin/models/badge_models.py +20 -0
  171. django_cfg/modules/django_admin/models/base.py +26 -0
  172. django_cfg/modules/django_admin/models/display_models.py +31 -0
  173. django_cfg/modules/django_admin/utils/badges.py +159 -0
  174. django_cfg/modules/django_admin/utils/displays.py +247 -0
  175. django_cfg/modules/django_currency/__init__.py +2 -2
  176. django_cfg/modules/django_currency/clients/__init__.py +2 -2
  177. django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
  178. django_cfg/modules/django_currency/core/converter.py +12 -12
  179. django_cfg/modules/django_currency/database/__init__.py +2 -2
  180. django_cfg/modules/django_currency/database/database_loader.py +93 -42
  181. django_cfg/modules/django_llm/llm/client.py +10 -2
  182. django_cfg/modules/django_tasks.py +54 -21
  183. django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
  184. django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
  185. django_cfg/modules/django_unfold/dashboard.py +14 -13
  186. django_cfg/modules/django_unfold/models/config.py +1 -1
  187. django_cfg/registry/core.py +7 -9
  188. django_cfg/registry/third_party.py +2 -2
  189. django_cfg/template_archive/django_sample.zip +0 -0
  190. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
  191. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
  192. django_cfg/apps/accounts/admin/activity.py +0 -96
  193. django_cfg/apps/accounts/admin/group.py +0 -17
  194. django_cfg/apps/accounts/admin/otp.py +0 -59
  195. django_cfg/apps/accounts/admin/registration_source.py +0 -97
  196. django_cfg/apps/accounts/admin/twilio_response.py +0 -227
  197. django_cfg/apps/accounts/admin/user.py +0 -300
  198. django_cfg/apps/agents/core/agent.py +0 -281
  199. django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
  200. django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
  201. django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
  202. django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
  203. django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
  204. django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
  205. django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
  206. django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
  207. django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
  208. django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
  209. django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
  210. django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
  211. django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
  212. django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
  213. django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
  214. django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
  215. django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
  216. django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
  217. django_cfg/apps/payments/config/constance/__init__.py +0 -22
  218. django_cfg/apps/payments/config/constance/config_service.py +0 -123
  219. django_cfg/apps/payments/config/constance/fields.py +0 -69
  220. django_cfg/apps/payments/config/constance/settings.py +0 -160
  221. django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
  222. django_cfg/apps/tasks/admin.py +0 -320
  223. django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
  224. django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
  225. django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
  226. django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
  227. django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
  228. django_cfg/apps/tasks/templates/tasks/base.html +0 -96
  229. django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
  230. django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
  231. django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
  232. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
  233. django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
  234. django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
  235. django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
  236. django_cfg/apps/tasks/views.py +0 -461
  237. django_cfg/management/commands/auto_generate.py +0 -486
  238. django_cfg/middleware/static_nocache.py +0 -55
  239. django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
  240. /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
  241. /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
  242. /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
  243. /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
  244. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
  245. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
  246. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -16,6 +16,7 @@ from ..types import (
16
16
  PaymentCreateRequest, PaymentStatusRequest, PaymentResult,
17
17
  PaymentData, ServiceOperationResult
18
18
  )
19
+ from ...models.managers.payment_managers import PaymentStatusUpdateFields
19
20
  from ...models import UniversalPayment, Currency, ProviderCurrency
20
21
  from ..providers import ProviderRegistry, get_provider_registry
21
22
 
@@ -49,12 +50,6 @@ class PaymentService(BaseService):
49
50
  if isinstance(request, dict):
50
51
  request = PaymentCreateRequest(**request)
51
52
 
52
- self.logger.info("Creating payment", extra={
53
- 'user_id': request.user_id,
54
- 'amount_usd': request.amount_usd,
55
- 'currency_code': request.currency_code,
56
- 'provider': request.provider
57
- })
58
53
 
59
54
  # Get user
60
55
  try:
@@ -94,6 +89,7 @@ class PaymentService(BaseService):
94
89
  network=currency.native_networks.first(), # Use first native network
95
90
  provider=request.provider,
96
91
  status=UniversalPayment.PaymentStatus.PENDING,
92
+ status_changed_at=timezone.now(), # Track initial status setting
97
93
  callback_url=request.callback_url,
98
94
  cancel_url=request.cancel_url,
99
95
  description=request.description,
@@ -103,12 +99,16 @@ class PaymentService(BaseService):
103
99
 
104
100
  payment = self._execute_with_transaction(create_payment_transaction)
105
101
 
102
+
106
103
  # Create payment with provider
107
- from ..providers.base import PaymentRequest as ProviderPaymentRequest
104
+ from ..providers.models import PaymentRequest as ProviderPaymentRequest
105
+
106
+ # Use provider_currency_code from metadata if available, otherwise use original currency_code
107
+ provider_currency_code = request.metadata.get('provider_currency_code', request.currency_code)
108
108
 
109
109
  provider_request = ProviderPaymentRequest(
110
110
  amount_usd=request.amount_usd,
111
- currency_code=request.currency_code,
111
+ currency_code=provider_currency_code, # Use provider-specific currency code
112
112
  order_id=str(payment.id),
113
113
  callback_url=request.callback_url,
114
114
  cancel_url=request.cancel_url,
@@ -118,50 +118,75 @@ class PaymentService(BaseService):
118
118
 
119
119
  provider_response = provider.create_payment(provider_request)
120
120
 
121
+
121
122
  # Update payment with provider response
122
123
  if provider_response.success:
123
124
  def update_payment_transaction():
124
125
  payment.provider_payment_id = provider_response.provider_payment_id
125
- payment.crypto_amount = provider_response.amount
126
+ payment.pay_amount = provider_response.amount # Fix: use pay_amount instead of crypto_amount
126
127
  payment.payment_url = provider_response.payment_url
127
128
  payment.qr_code_url = provider_response.qr_code_url
128
- payment.wallet_address = provider_response.wallet_address
129
+ payment.pay_address = provider_response.wallet_address # Fix: use pay_address instead of wallet_address
129
130
  if provider_response.expires_at:
130
131
  payment.expires_at = provider_response.expires_at
131
132
  payment.save()
132
133
  return payment
133
134
 
134
135
  payment = self._execute_with_transaction(update_payment_transaction)
136
+
137
+ # Convert to PaymentData using our helper method
138
+ payment_data = self._convert_payment_to_data(payment)
139
+
140
+ self._log_operation(
141
+ "create_payment",
142
+ True,
143
+ payment_id=str(payment.id),
144
+ user_id=request.user_id,
145
+ amount_usd=request.amount_usd
146
+ )
147
+
148
+ return PaymentResult(
149
+ success=True,
150
+ message="Payment created successfully",
151
+ payment_id=str(payment.id),
152
+ status=payment.status,
153
+ amount_usd=payment.amount_usd,
154
+ crypto_amount=payment.pay_amount,
155
+ currency_code=payment.currency.code,
156
+ payment_url=payment.payment_url,
157
+ expires_at=payment.expires_at,
158
+ data={'payment': payment_data.model_dump()}
159
+ )
160
+
135
161
  else:
136
162
  # Mark payment as failed if provider creation failed
163
+ self.logger.error("❌ PAYMENT SERVICE: Provider creation failed", extra={
164
+ 'payment_id': str(payment.id),
165
+ 'provider_error': getattr(provider_response, 'error_message', 'Unknown error')
166
+ })
137
167
  payment.mark_failed(
138
168
  reason=provider_response.error_message,
139
169
  error_code="provider_creation_failed"
140
170
  )
141
-
142
- # Convert to PaymentData using our helper method
143
- payment_data = self._convert_payment_to_data(payment)
144
-
145
- self._log_operation(
146
- "create_payment",
147
- True,
148
- payment_id=str(payment.id),
149
- user_id=request.user_id,
150
- amount_usd=request.amount_usd
151
- )
152
-
153
- return PaymentResult(
154
- success=True,
155
- message="Payment created successfully",
156
- payment_id=str(payment.id),
157
- status=payment.status,
158
- amount_usd=payment.amount_usd,
159
- crypto_amount=payment.pay_amount,
160
- currency_code=payment.currency.code,
161
- payment_url=payment.payment_url,
162
- expires_at=payment.expires_at,
163
- data={'payment': payment_data.model_dump()}
164
- )
171
+
172
+ # Return error result when provider fails
173
+ self._log_operation(
174
+ "create_payment",
175
+ False,
176
+ payment_id=str(payment.id),
177
+ user_id=request.user_id,
178
+ amount_usd=request.amount_usd,
179
+ error=provider_response.error_message
180
+ )
181
+
182
+ return PaymentResult(
183
+ success=False,
184
+ message=provider_response.error_message or "Payment creation failed",
185
+ error_code="provider_creation_failed",
186
+ payment_id=str(payment.id),
187
+ status=payment.status,
188
+ data={'error_details': getattr(provider_response, 'raw_response', {})}
189
+ )
165
190
 
166
191
  except Exception as e:
167
192
  return PaymentResult(**self._handle_exception(
@@ -362,21 +387,114 @@ class PaymentService(BaseService):
362
387
  )
363
388
 
364
389
  def _check_provider_status(self, payment: UniversalPayment) -> ServiceOperationResult:
365
- """Check payment status with provider."""
390
+ """Check payment status with provider and update database if needed."""
366
391
  try:
367
- # This would integrate with provider services
368
- # For now, return success without changes
392
+ if not payment.provider_payment_id:
393
+ return self._create_success_result(
394
+ "No provider payment ID, skipping provider check",
395
+ {'status_changed': False}
396
+ )
397
+
398
+ # Get provider instance
399
+ provider = self.provider_registry.get_provider(payment.provider)
400
+ if not provider:
401
+ return self._create_error_result(
402
+ f"Provider {payment.provider} not available",
403
+ "provider_not_available"
404
+ )
405
+
406
+ # Check status with provider
407
+ provider_response = provider.get_payment_status(payment.provider_payment_id)
408
+
409
+ if not provider_response.success:
410
+ self.logger.warning(f"Provider status check failed for payment {payment.id}", extra={
411
+ 'payment_id': str(payment.id),
412
+ 'provider_payment_id': payment.provider_payment_id,
413
+ 'error': provider_response.error_message
414
+ })
415
+ return self._create_error_result(
416
+ f"Provider status check failed: {provider_response.error_message}",
417
+ "provider_check_failed"
418
+ )
419
+
420
+ # Map provider status to our status
421
+ original_status = payment.status
422
+ new_status = self._map_provider_status(provider_response.status, payment.provider)
423
+
424
+ status_changed = False
425
+
426
+ # Update payment if status changed
427
+ if new_status and new_status != original_status:
428
+ def update_payment_transaction():
429
+ nonlocal status_changed
430
+
431
+ # Update status
432
+ payment.status = new_status
433
+ payment.status_changed_at = timezone.now() # Track when status changed
434
+
435
+ # Update other fields from provider response
436
+ if provider_response.transaction_hash and not payment.transaction_hash:
437
+ payment.transaction_hash = provider_response.transaction_hash
438
+
439
+ if provider_response.confirmations_count is not None:
440
+ payment.confirmations_count = provider_response.confirmations_count
441
+
442
+ # Mark as completed if status is completed/confirmed
443
+ if new_status in ['completed', 'confirmed'] and not payment.completed_at:
444
+ payment.completed_at = timezone.now()
445
+
446
+ payment.save()
447
+ status_changed = True
448
+
449
+ return True
450
+
451
+ # Execute in transaction
452
+ self._execute_with_transaction(update_payment_transaction)
453
+
454
+ self.logger.info(f"Payment status updated from provider", extra={
455
+ 'payment_id': str(payment.id),
456
+ 'provider_payment_id': payment.provider_payment_id,
457
+ 'status_change': f"{original_status} -> {new_status}",
458
+ 'provider': payment.provider
459
+ })
460
+
369
461
  return self._create_success_result(
370
- "Provider status checked",
371
- {'status_changed': False}
462
+ f"Provider status checked: {original_status} -> {new_status}" if status_changed else "No status change",
463
+ {
464
+ 'status_changed': status_changed,
465
+ 'original_status': original_status,
466
+ 'new_status': new_status,
467
+ 'provider_response': provider_response.raw_response
468
+ }
372
469
  )
373
470
 
374
471
  except Exception as e:
472
+ self.logger.error(f"Provider status check failed", extra={
473
+ 'payment_id': str(payment.id),
474
+ 'error': str(e)
475
+ })
375
476
  return self._create_error_result(
376
477
  f"Provider check failed: {e}",
377
478
  "provider_check_failed"
378
479
  )
379
480
 
481
+ def _map_provider_status(self, provider_status: str, provider: str) -> Optional[str]:
482
+ """Map provider-specific status to universal status."""
483
+ if provider == 'nowpayments':
484
+ status_mapping = {
485
+ 'waiting': 'pending',
486
+ 'confirming': 'confirming',
487
+ 'confirmed': 'confirmed',
488
+ 'finished': 'completed',
489
+ 'failed': 'failed',
490
+ 'refunded': 'refunded',
491
+ 'expired': 'expired'
492
+ }
493
+ return status_mapping.get(provider_status.lower())
494
+
495
+ # Default mapping for unknown providers
496
+ return provider_status.lower() if provider_status else None
497
+
380
498
  def get_user_payments(
381
499
  self,
382
500
  user_id: int,
@@ -477,3 +595,112 @@ class PaymentService(BaseService):
477
595
 
478
596
  except Exception as e:
479
597
  return self._handle_exception("get_payment_stats", e)
598
+
599
+ def _check_provider_status(self, payment: 'UniversalPayment') -> ServiceOperationResult:
600
+ """
601
+ Check payment status with provider and update if changed.
602
+
603
+ Args:
604
+ payment: Payment object to check
605
+
606
+ Returns:
607
+ ServiceOperationResult: Result with status_changed flag
608
+ """
609
+ try:
610
+ from ..providers.registry import ProviderRegistry
611
+ from django.db import transaction
612
+
613
+ self.logger.debug("Checking provider status", extra={
614
+ 'payment_id': str(payment.id),
615
+ 'current_status': payment.status,
616
+ 'provider': payment.provider
617
+ })
618
+
619
+ # Get provider instance
620
+ registry = ProviderRegistry()
621
+ provider = registry.get_provider(payment.provider)
622
+
623
+ if not provider:
624
+ return self._create_error_result(
625
+ f"Provider {payment.provider} not found",
626
+ "provider_not_found"
627
+ )
628
+
629
+ # Get status from provider
630
+ provider_response = provider.get_payment_status(payment.provider_payment_id)
631
+
632
+ if not provider_response.success:
633
+ self.logger.warning("Provider status check failed", extra={
634
+ 'payment_id': str(payment.id),
635
+ 'provider': payment.provider,
636
+ 'error': provider_response.error_message
637
+ })
638
+ return self._create_error_result(
639
+ f"Provider status check failed: {provider_response.error_message}",
640
+ "provider_check_failed"
641
+ )
642
+
643
+ # Map provider status to universal status
644
+ provider_status = provider_response.data.get('status', '').lower()
645
+ status_mapping = {
646
+ 'waiting': UniversalPayment.PaymentStatus.PENDING,
647
+ 'confirming': UniversalPayment.PaymentStatus.PENDING,
648
+ 'confirmed': UniversalPayment.PaymentStatus.COMPLETED,
649
+ 'sending': UniversalPayment.PaymentStatus.PENDING,
650
+ 'partially_paid': UniversalPayment.PaymentStatus.PENDING,
651
+ 'finished': UniversalPayment.PaymentStatus.COMPLETED,
652
+ 'failed': UniversalPayment.PaymentStatus.FAILED,
653
+ 'refunded': UniversalPayment.PaymentStatus.FAILED,
654
+ 'expired': UniversalPayment.PaymentStatus.EXPIRED,
655
+ }
656
+
657
+ new_status = status_mapping.get(provider_status, payment.status)
658
+ status_changed = new_status != payment.status
659
+
660
+ # Update payment if status changed
661
+ if status_changed:
662
+ with transaction.atomic():
663
+ # Prepare extra fields from provider response
664
+ provider_data = provider_response.data
665
+
666
+ extra_fields = PaymentStatusUpdateFields(
667
+ transaction_hash=provider_data.get('transaction_hash'),
668
+ confirmations_count=provider_data.get('confirmations_count')
669
+ )
670
+
671
+ # Use manager method for consistent status updates
672
+ from ...models import UniversalPayment
673
+ success = UniversalPayment.objects.update_payment_status(
674
+ payment, new_status, extra_fields
675
+ )
676
+
677
+ if not success:
678
+ return self._create_error_result(
679
+ "Failed to update payment status",
680
+ "status_update_failed"
681
+ )
682
+
683
+ self.logger.info("Payment status updated", extra={
684
+ 'payment_id': str(payment.id),
685
+ 'old_status': payment.status,
686
+ 'new_status': new_status,
687
+ 'provider_status': provider_status
688
+ })
689
+
690
+ return self._create_success_result(
691
+ "Provider status checked",
692
+ {
693
+ 'status_changed': status_changed,
694
+ 'old_status': payment.status if not status_changed else None,
695
+ 'new_status': new_status,
696
+ 'provider_status': provider_status,
697
+ 'provider_response': provider_response.data
698
+ }
699
+ )
700
+
701
+ except Exception as e:
702
+ self.logger.error("Error checking provider status", extra={
703
+ 'payment_id': str(payment.id),
704
+ 'error': str(e)
705
+ })
706
+ return self._handle_exception("_check_provider_status", e)
@@ -7,6 +7,7 @@ Provider implementations with unified interface and Pydantic validation.
7
7
  from .base import BaseProvider
8
8
  from .nowpayments import NowPaymentsProvider
9
9
  from .registry import ProviderRegistry, get_provider_registry, initialize_providers
10
+ from .sync_service import ProviderSyncService, get_provider_sync_service
10
11
 
11
12
  __all__ = [
12
13
  'BaseProvider',
@@ -14,4 +15,6 @@ __all__ = [
14
15
  'ProviderRegistry',
15
16
  'get_provider_registry',
16
17
  'initialize_providers',
18
+ 'ProviderSyncService',
19
+ 'get_provider_sync_service',
17
20
  ]