django-cfg 1.3.7__py3-none-any.whl → 1.3.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/admin/__init__.py +24 -8
- django_cfg/apps/accounts/admin/activity_admin.py +146 -0
- django_cfg/apps/accounts/admin/filters.py +98 -22
- django_cfg/apps/accounts/admin/group_admin.py +86 -0
- django_cfg/apps/accounts/admin/inlines.py +42 -13
- django_cfg/apps/accounts/admin/otp_admin.py +115 -0
- django_cfg/apps/accounts/admin/registration_admin.py +173 -0
- django_cfg/apps/accounts/admin/resources.py +123 -19
- django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
- django_cfg/apps/accounts/admin/user_admin.py +362 -0
- django_cfg/apps/agents/admin/__init__.py +17 -4
- django_cfg/apps/agents/admin/execution_admin.py +204 -183
- django_cfg/apps/agents/admin/registry_admin.py +230 -255
- django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
- django_cfg/apps/agents/core/__init__.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +221 -0
- django_cfg/apps/agents/core/exceptions.py +14 -0
- django_cfg/apps/agents/core/orchestrator.py +18 -3
- django_cfg/apps/knowbase/admin/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
- django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
- django_cfg/apps/knowbase/admin/document_admin.py +269 -262
- django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
- django_cfg/apps/knowbase/config/settings.py +21 -4
- django_cfg/apps/knowbase/views/chat_views.py +3 -0
- django_cfg/apps/leads/admin/__init__.py +3 -1
- django_cfg/apps/leads/admin/leads_admin.py +235 -35
- django_cfg/apps/maintenance/admin/__init__.py +2 -2
- django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
- django_cfg/apps/maintenance/admin/log_admin.py +143 -61
- django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
- django_cfg/apps/maintenance/admin/site_admin.py +213 -352
- django_cfg/apps/newsletter/admin/__init__.py +29 -2
- django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
- django_cfg/apps/payments/admin/__init__.py +18 -27
- django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
- django_cfg/apps/payments/admin/balance_admin.py +166 -632
- django_cfg/apps/payments/admin/currencies_admin.py +235 -607
- django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
- django_cfg/apps/payments/admin/filters.py +83 -3
- django_cfg/apps/payments/admin/networks_admin.py +269 -0
- django_cfg/apps/payments/admin/payments_admin.py +183 -460
- django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
- django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
- django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
- django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
- django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
- django_cfg/apps/payments/config/__init__.py +14 -15
- django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
- django_cfg/apps/payments/config/helpers.py +8 -13
- django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
- django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
- django_cfg/apps/payments/middleware/api_access.py +32 -6
- django_cfg/apps/payments/migrations/0001_initial.py +33 -46
- django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
- django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
- django_cfg/apps/payments/models/balance.py +12 -0
- django_cfg/apps/payments/models/currencies.py +106 -32
- django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
- django_cfg/apps/payments/models/payments.py +94 -0
- django_cfg/apps/payments/services/core/base.py +4 -4
- django_cfg/apps/payments/services/core/currency_service.py +35 -28
- django_cfg/apps/payments/services/core/payment_service.py +266 -39
- django_cfg/apps/payments/services/providers/__init__.py +3 -0
- django_cfg/apps/payments/services/providers/base.py +303 -41
- django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
- django_cfg/apps/payments/services/providers/models/base.py +145 -0
- django_cfg/apps/payments/services/providers/models/providers.py +87 -0
- django_cfg/apps/payments/services/providers/models/universal.py +48 -0
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
- django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
- django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
- django_cfg/apps/payments/services/providers/registry.py +9 -37
- django_cfg/apps/payments/services/providers/sync_service.py +277 -0
- django_cfg/apps/payments/services/types/requests.py +19 -7
- django_cfg/apps/payments/signals/payment_signals.py +31 -2
- django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
- django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
- django_cfg/apps/payments/tasks/__init__.py +39 -0
- django_cfg/apps/payments/tasks/types.py +73 -0
- django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
- django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
- django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
- django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
- django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
- django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
- django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
- django_cfg/apps/payments/urls.py +3 -2
- django_cfg/apps/payments/urls_admin.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +8 -5
- django_cfg/apps/payments/views/overview/services.py +2 -2
- django_cfg/apps/payments/views/serializers/currencies.py +22 -8
- django_cfg/apps/support/admin/__init__.py +10 -1
- django_cfg/apps/support/admin/support_admin.py +338 -141
- django_cfg/apps/tasks/admin/__init__.py +11 -0
- django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
- django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
- django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
- django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
- django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
- django_cfg/apps/tasks/tasks/__init__.py +10 -0
- django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
- django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
- django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
- django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
- django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
- django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
- django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
- django_cfg/apps/tasks/urls.py +2 -2
- django_cfg/apps/tasks/urls_admin.py +2 -2
- django_cfg/apps/tasks/utils/__init__.py +1 -0
- django_cfg/apps/tasks/utils/simulator.py +356 -0
- django_cfg/apps/tasks/views/__init__.py +16 -0
- django_cfg/apps/tasks/views/api.py +569 -0
- django_cfg/apps/tasks/views/dashboard.py +58 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +10 -5
- django_cfg/core/generation.py +1 -1
- django_cfg/core/integration/__init__.py +21 -0
- django_cfg/management/commands/__init__.py +13 -1
- django_cfg/management/commands/migrate_all.py +9 -3
- django_cfg/management/commands/migrator.py +11 -6
- django_cfg/management/commands/rundramatiq.py +3 -2
- django_cfg/management/commands/rundramatiq_simulator.py +430 -0
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/models/api_keys.py +115 -0
- django_cfg/models/constance.py +0 -11
- django_cfg/models/payments.py +137 -3
- django_cfg/modules/django_admin/__init__.py +64 -0
- django_cfg/modules/django_admin/decorators/__init__.py +13 -0
- django_cfg/modules/django_admin/decorators/actions.py +106 -0
- django_cfg/modules/django_admin/decorators/display.py +106 -0
- django_cfg/modules/django_admin/mixins/__init__.py +14 -0
- django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
- django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
- django_cfg/modules/django_admin/models/__init__.py +20 -0
- django_cfg/modules/django_admin/models/action_models.py +33 -0
- django_cfg/modules/django_admin/models/badge_models.py +20 -0
- django_cfg/modules/django_admin/models/base.py +26 -0
- django_cfg/modules/django_admin/models/display_models.py +31 -0
- django_cfg/modules/django_admin/utils/badges.py +159 -0
- django_cfg/modules/django_admin/utils/displays.py +247 -0
- django_cfg/modules/django_currency/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
- django_cfg/modules/django_currency/core/converter.py +12 -12
- django_cfg/modules/django_currency/database/__init__.py +2 -2
- django_cfg/modules/django_currency/database/database_loader.py +93 -42
- django_cfg/modules/django_llm/llm/client.py +10 -2
- django_cfg/modules/django_tasks.py +54 -21
- django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
- django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
- django_cfg/modules/django_unfold/dashboard.py +14 -13
- django_cfg/modules/django_unfold/models/config.py +1 -1
- django_cfg/registry/core.py +7 -9
- django_cfg/registry/third_party.py +2 -2
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
- django_cfg/apps/accounts/admin/activity.py +0 -96
- django_cfg/apps/accounts/admin/group.py +0 -17
- django_cfg/apps/accounts/admin/otp.py +0 -59
- django_cfg/apps/accounts/admin/registration_source.py +0 -97
- django_cfg/apps/accounts/admin/twilio_response.py +0 -227
- django_cfg/apps/accounts/admin/user.py +0 -300
- django_cfg/apps/agents/core/agent.py +0 -281
- django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
- django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
- django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
- django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
- django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
- django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
- django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
- django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
- django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
- django_cfg/apps/payments/config/constance/__init__.py +0 -22
- django_cfg/apps/payments/config/constance/config_service.py +0 -123
- django_cfg/apps/payments/config/constance/fields.py +0 -69
- django_cfg/apps/payments/config/constance/settings.py +0 -160
- django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
- django_cfg/apps/tasks/admin.py +0 -320
- django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
- django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
- django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
- django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
- django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
- django_cfg/apps/tasks/templates/tasks/base.html +0 -96
- django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
- django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
- django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
- django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
- django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
- django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
- django_cfg/apps/tasks/views.py +0 -461
- django_cfg/management/commands/auto_generate.py +0 -486
- django_cfg/middleware/static_nocache.py +0 -55
- django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
- /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -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.
|
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=
|
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.
|
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.
|
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
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
368
|
-
|
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
|
-
{
|
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
|
]
|