django-cfg 1.3.9__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/payments/admin/networks_admin.py +12 -1
- django_cfg/apps/payments/admin/payments_admin.py +13 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +62 -14
- 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 +33 -3
- django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +96 -45
- 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/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/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/payment_service.py +265 -38
- django_cfg/apps/payments/services/providers/base.py +209 -3
- django_cfg/apps/payments/services/providers/models/__init__.py +2 -0
- django_cfg/apps/payments/services/providers/models/base.py +25 -2
- django_cfg/apps/payments/services/providers/nowpayments/models.py +2 -2
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +57 -9
- django_cfg/apps/payments/services/providers/registry.py +5 -5
- 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 +6 -1
- django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +35 -26
- django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
- django_cfg/apps/payments/urls.py +3 -2
- django_cfg/apps/payments/views/api/currencies.py +3 -0
- django_cfg/apps/payments/views/serializers/currencies.py +18 -5
- django_cfg/apps/tasks/admin/tasks_admin.py +2 -2
- 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/core/integration/__init__.py +21 -0
- django_cfg/management/commands/rundramatiq_simulator.py +430 -0
- django_cfg/models/constance.py +0 -11
- django_cfg/models/payments.py +137 -3
- django_cfg/modules/django_tasks.py +54 -21
- django_cfg/registry/core.py +4 -9
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -2
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/RECORD +84 -152
- 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/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +0 -26
- django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +0 -28
- django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +0 -30
- 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/app_agent_diagnose.py +0 -470
- django_cfg/management/commands/app_agent_generate.py +0 -342
- django_cfg/management/commands/app_agent_info.py +0 -308
- django_cfg/management/commands/auto_generate.py +0 -486
- django_cfg/modules/django_app_agent/__init__.py +0 -87
- django_cfg/modules/django_app_agent/agents/__init__.py +0 -40
- django_cfg/modules/django_app_agent/agents/base/__init__.py +0 -24
- django_cfg/modules/django_app_agent/agents/base/agent.py +0 -354
- django_cfg/modules/django_app_agent/agents/base/context.py +0 -236
- django_cfg/modules/django_app_agent/agents/base/executor.py +0 -430
- django_cfg/modules/django_app_agent/agents/generation/__init__.py +0 -12
- django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +0 -15
- django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +0 -147
- django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +0 -99
- django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +0 -32
- django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +0 -290
- django_cfg/modules/django_app_agent/agents/interfaces.py +0 -376
- django_cfg/modules/django_app_agent/core/__init__.py +0 -33
- django_cfg/modules/django_app_agent/core/config.py +0 -300
- django_cfg/modules/django_app_agent/core/exceptions.py +0 -359
- django_cfg/modules/django_app_agent/models/__init__.py +0 -71
- django_cfg/modules/django_app_agent/models/base.py +0 -283
- django_cfg/modules/django_app_agent/models/context.py +0 -496
- django_cfg/modules/django_app_agent/models/enums.py +0 -481
- django_cfg/modules/django_app_agent/models/requests.py +0 -500
- django_cfg/modules/django_app_agent/models/responses.py +0 -585
- django_cfg/modules/django_app_agent/pytest.ini +0 -6
- django_cfg/modules/django_app_agent/services/__init__.py +0 -42
- django_cfg/modules/django_app_agent/services/app_generator/__init__.py +0 -30
- django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +0 -133
- django_cfg/modules/django_app_agent/services/app_generator/context.py +0 -40
- django_cfg/modules/django_app_agent/services/app_generator/main.py +0 -202
- django_cfg/modules/django_app_agent/services/app_generator/structure.py +0 -316
- django_cfg/modules/django_app_agent/services/app_generator/validation.py +0 -125
- django_cfg/modules/django_app_agent/services/base.py +0 -437
- django_cfg/modules/django_app_agent/services/context_builder/__init__.py +0 -34
- django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +0 -141
- django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +0 -276
- django_cfg/modules/django_app_agent/services/context_builder/main.py +0 -272
- django_cfg/modules/django_app_agent/services/context_builder/models.py +0 -40
- django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +0 -85
- django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +0 -31
- django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +0 -311
- django_cfg/modules/django_app_agent/services/project_scanner/main.py +0 -221
- django_cfg/modules/django_app_agent/services/project_scanner/models.py +0 -59
- django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +0 -94
- django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +0 -28
- django_cfg/modules/django_app_agent/services/questioning_service/main.py +0 -273
- django_cfg/modules/django_app_agent/services/questioning_service/models.py +0 -111
- django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +0 -251
- django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +0 -347
- django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +0 -356
- django_cfg/modules/django_app_agent/services/report_service.py +0 -332
- django_cfg/modules/django_app_agent/services/template_manager/__init__.py +0 -18
- django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +0 -236
- django_cfg/modules/django_app_agent/services/template_manager/main.py +0 -159
- django_cfg/modules/django_app_agent/services/template_manager/models.py +0 -36
- django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +0 -100
- django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +0 -105
- django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +0 -31
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +0 -44
- django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +0 -81
- django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +0 -107
- django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +0 -139
- django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +0 -91
- django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +0 -195
- django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +0 -35
- django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +0 -211
- django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +0 -200
- django_cfg/modules/django_app_agent/services/validation_service/__init__.py +0 -25
- django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +0 -333
- django_cfg/modules/django_app_agent/services/validation_service/main.py +0 -242
- django_cfg/modules/django_app_agent/services/validation_service/models.py +0 -66
- django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +0 -352
- django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +0 -272
- django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +0 -203
- django_cfg/modules/django_app_agent/ui/__init__.py +0 -25
- django_cfg/modules/django_app_agent/ui/cli.py +0 -419
- django_cfg/modules/django_app_agent/ui/rich_components.py +0 -622
- django_cfg/modules/django_app_agent/utils/__init__.py +0 -38
- django_cfg/modules/django_app_agent/utils/logging.py +0 -360
- django_cfg/modules/django_app_agent/utils/validation.py +0 -417
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.9.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -23,9 +23,14 @@ from django_cfg.apps.payments.admin_interface.serializers import (
|
|
23
23
|
WebhookActionSerializer,
|
24
24
|
WebhookActionResultSerializer,
|
25
25
|
)
|
26
|
-
from django_cfg.apps.payments.services.core.webhook_service import WebhookService
|
27
26
|
from django_cfg.apps.payments.models import UniversalPayment
|
28
27
|
from django_cfg.modules.django_logger import get_logger
|
28
|
+
from django_cfg.apps.payments.services.integrations.ngrok_service import (
|
29
|
+
get_all_webhook_urls,
|
30
|
+
get_api_base_url,
|
31
|
+
is_ngrok_available
|
32
|
+
)
|
33
|
+
from django_cfg.apps.payments.services.core.webhook_service import WebhookService
|
29
34
|
|
30
35
|
logger = get_logger("admin_webhook_api")
|
31
36
|
|
@@ -41,31 +46,57 @@ class AdminWebhookViewSet(AdminReadOnlyViewSet):
|
|
41
46
|
# No model - this is for webhook configuration data
|
42
47
|
serializer_class = WebhookStatsSerializer
|
43
48
|
|
49
|
+
def __init__(self, **kwargs):
|
50
|
+
"""Initialize with ngrok service."""
|
51
|
+
super().__init__(**kwargs)
|
52
|
+
|
53
|
+
self.get_webhook_urls = get_all_webhook_urls
|
54
|
+
self.get_base_url = get_api_base_url
|
55
|
+
self.is_ngrok_active = is_ngrok_available
|
56
|
+
|
44
57
|
def list(self, request):
|
45
|
-
"""List webhook providers and configurations."""
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
58
|
+
"""List webhook providers and configurations with real ngrok URLs."""
|
59
|
+
# Get real webhook URLs
|
60
|
+
webhook_urls = self.get_webhook_urls()
|
61
|
+
base_url = self.get_base_url()
|
62
|
+
ngrok_active = self.is_ngrok_active()
|
63
|
+
|
64
|
+
# Get real provider data based on actual payments
|
65
|
+
active_providers = UniversalPayment.objects.values('provider').distinct()
|
66
|
+
|
67
|
+
providers_data = []
|
68
|
+
for provider_data in active_providers:
|
69
|
+
provider_name = provider_data['provider']
|
70
|
+
provider_payments = UniversalPayment.objects.filter(provider=provider_name)
|
71
|
+
|
72
|
+
# Calculate real statistics
|
73
|
+
total_payments = provider_payments.count()
|
74
|
+
last_payment = provider_payments.order_by('-created_at').first()
|
75
|
+
|
76
|
+
provider_info = {
|
77
|
+
'name': provider_name,
|
78
|
+
'display_name': provider_name.title(),
|
79
|
+
'enabled': total_payments > 0,
|
80
|
+
'webhook_url': webhook_urls.get(provider_name, f"{base_url}/api/webhooks/{provider_name}/"),
|
53
81
|
'supported_events': ['payment.created', 'payment.completed', 'payment.failed'],
|
54
|
-
'last_ping':
|
55
|
-
'status': 'active'
|
56
|
-
|
57
|
-
|
58
|
-
'name': 'stripe',
|
59
|
-
'display_name': 'Stripe',
|
60
|
-
'enabled': False,
|
61
|
-
'webhook_url': 'https://api.stripe.com/v1/webhooks',
|
62
|
-
'supported_events': ['payment_intent.succeeded', 'payment_intent.payment_failed'],
|
63
|
-
'last_ping': None,
|
64
|
-
'status': 'inactive'
|
82
|
+
'last_ping': last_payment.created_at if last_payment else None,
|
83
|
+
'status': 'active' if total_payments > 0 else 'inactive',
|
84
|
+
'ngrok_active': ngrok_active,
|
85
|
+
'base_url': base_url
|
65
86
|
}
|
66
|
-
|
87
|
+
providers_data.append(provider_info)
|
67
88
|
|
68
|
-
|
89
|
+
# Add ngrok status to response
|
90
|
+
response_data = {
|
91
|
+
'providers': providers_data,
|
92
|
+
'ngrok_status': {
|
93
|
+
'active': ngrok_active,
|
94
|
+
'base_url': base_url,
|
95
|
+
'webhook_urls': webhook_urls
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
serializer = self.get_serializer(response_data)
|
69
100
|
return Response(serializer.data)
|
70
101
|
|
71
102
|
@action(detail=False, methods=['get'])
|
@@ -126,8 +157,17 @@ class AdminWebhookEventViewSet(AdminReadOnlyViewSet):
|
|
126
157
|
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
|
127
158
|
filterset_fields = ['event_type', 'status', 'provider']
|
128
159
|
search_fields = ['event_type', 'webhook_url']
|
129
|
-
ordering_fields = ['
|
130
|
-
ordering = ['-
|
160
|
+
ordering_fields = ['timestamp', 'event_type', 'status']
|
161
|
+
ordering = ['-timestamp']
|
162
|
+
|
163
|
+
def __init__(self, **kwargs):
|
164
|
+
"""Initialize with webhook and ngrok services."""
|
165
|
+
super().__init__(**kwargs)
|
166
|
+
|
167
|
+
self.webhook_service = WebhookService()
|
168
|
+
self.get_webhook_urls = get_all_webhook_urls
|
169
|
+
self.get_base_url = get_api_base_url
|
170
|
+
self.is_ngrok_active = is_ngrok_available
|
131
171
|
|
132
172
|
def get_queryset(self):
|
133
173
|
"""Get webhook events queryset."""
|
@@ -138,9 +178,9 @@ class AdminWebhookEventViewSet(AdminReadOnlyViewSet):
|
|
138
178
|
def list(self, request, webhook_pk=None):
|
139
179
|
"""List webhook events with filtering and pagination."""
|
140
180
|
# Get filter parameters
|
141
|
-
event_type = request.
|
142
|
-
status_filter = request.
|
143
|
-
provider = request.
|
181
|
+
event_type = request.GET.get('event_type')
|
182
|
+
status_filter = request.GET.get('status')
|
183
|
+
provider = request.GET.get('provider')
|
144
184
|
|
145
185
|
# Get real payment data to generate realistic mock events
|
146
186
|
payments = UniversalPayment.objects.all()[:50] # Limit for performance
|
@@ -152,23 +192,28 @@ class AdminWebhookEventViewSet(AdminReadOnlyViewSet):
|
|
152
192
|
event_types = ['payment.created', 'payment.completed'] if payment.status == 'completed' else ['payment.created']
|
153
193
|
|
154
194
|
for event_type_name in event_types:
|
195
|
+
# Create payload for the event
|
196
|
+
payload = {
|
197
|
+
'payment_id': str(payment.id),
|
198
|
+
'amount': str(payment.amount_usd),
|
199
|
+
'currency': payment.currency.code if payment.currency else payment.currency_code,
|
200
|
+
'status': payment.status,
|
201
|
+
'timestamp': payment.created_at.isoformat()
|
202
|
+
}
|
203
|
+
|
155
204
|
event = {
|
156
|
-
'id': f"
|
205
|
+
'id': int(str(hash(f"{payment.id}_{event_type_name}_{i}"))[:8], 16),
|
206
|
+
'provider': payment.provider,
|
157
207
|
'event_type': event_type_name,
|
158
|
-
'webhook_url': f'https://example.com/webhook/{payment.id}',
|
159
208
|
'status': 'success' if i % 5 != 0 else 'failed',
|
160
|
-
'
|
161
|
-
'
|
162
|
-
'
|
163
|
-
'
|
164
|
-
'
|
165
|
-
'
|
166
|
-
|
167
|
-
|
168
|
-
'currency': payment.currency,
|
169
|
-
'status': payment.status,
|
170
|
-
'timestamp': payment.created_at.isoformat()
|
171
|
-
}
|
209
|
+
'timestamp': payment.created_at,
|
210
|
+
'payload_size': len(str(payload)),
|
211
|
+
'response_time': 50 + (i % 200),
|
212
|
+
'retry_count': 0 if i % 5 != 0 else 2,
|
213
|
+
'error_message': '' if i % 5 != 0 else 'Connection timeout',
|
214
|
+
'payload_preview': str(payload)[:200],
|
215
|
+
'response_status_code': 200 if i % 5 != 0 else 500,
|
216
|
+
'webhook_url': self.get_webhook_urls().get(payment.provider, f"{self.get_base_url()}/api/webhooks/{payment.provider}/"),
|
172
217
|
}
|
173
218
|
|
174
219
|
# Apply filters
|
@@ -181,12 +226,13 @@ class AdminWebhookEventViewSet(AdminReadOnlyViewSet):
|
|
181
226
|
|
182
227
|
events.append(event)
|
183
228
|
|
184
|
-
# Sort by
|
185
|
-
events
|
229
|
+
# Sort by timestamp descending (only if events exist)
|
230
|
+
if events:
|
231
|
+
events.sort(key=lambda x: x.get('timestamp', timezone.now()), reverse=True)
|
186
232
|
|
187
233
|
# Pagination
|
188
234
|
page_size = 20
|
189
|
-
page = int(request.
|
235
|
+
page = int(request.GET.get('page', 1))
|
190
236
|
start = (page - 1) * page_size
|
191
237
|
end = start + page_size
|
192
238
|
paginated_events = events[start:end]
|
@@ -197,7 +243,12 @@ class AdminWebhookEventViewSet(AdminReadOnlyViewSet):
|
|
197
243
|
'page': page,
|
198
244
|
'per_page': page_size,
|
199
245
|
'has_next': end < len(events),
|
200
|
-
'has_previous': page > 1
|
246
|
+
'has_previous': page > 1,
|
247
|
+
'ngrok_status': {
|
248
|
+
'active': self.is_ngrok_active(),
|
249
|
+
'base_url': self.get_base_url(),
|
250
|
+
'webhook_urls': self.get_webhook_urls()
|
251
|
+
}
|
201
252
|
}
|
202
253
|
|
203
254
|
serializer = self.get_serializer(response_data)
|
@@ -51,7 +51,7 @@ class PaymentDetailView(AdminTemplateViewMixin, LoginRequiredMixin, DetailView):
|
|
51
51
|
|
52
52
|
def get_queryset(self):
|
53
53
|
"""Optimized queryset with related objects."""
|
54
|
-
return UniversalPayment.objects.select_related('user')
|
54
|
+
return UniversalPayment.objects.select_related('user', 'currency', 'network')
|
55
55
|
|
56
56
|
def get_context_data(self, **kwargs):
|
57
57
|
"""Add detail context data."""
|
@@ -59,7 +59,11 @@ class PaymentDetailView(AdminTemplateViewMixin, LoginRequiredMixin, DetailView):
|
|
59
59
|
|
60
60
|
payment = self.get_object()
|
61
61
|
|
62
|
+
# Force refresh from database to get latest data
|
63
|
+
payment.refresh_from_db()
|
64
|
+
|
62
65
|
context.update({
|
66
|
+
'payment': payment,
|
63
67
|
'page_title': f'Payment {payment.internal_payment_id or payment.id}',
|
64
68
|
'page_subtitle': f'Payment details and transaction history',
|
65
69
|
'show_actions': True,
|
@@ -1,42 +1,41 @@
|
|
1
1
|
"""
|
2
2
|
Configuration module for the Universal Payment System v2.0.
|
3
3
|
|
4
|
-
Provides
|
5
|
-
- django-cfg integration (
|
6
|
-
- Constance integration (dynamic config)
|
4
|
+
Provides unified configuration through BaseCfgAutoModule:
|
5
|
+
- django-cfg integration (all configuration)
|
7
6
|
- Configuration utilities and helpers
|
8
7
|
"""
|
9
8
|
|
10
|
-
# Django-cfg integration
|
9
|
+
# Django-cfg integration (BaseCfgAutoModule)
|
11
10
|
from .django_cfg_integration import (
|
11
|
+
PaymentsConfigManager,
|
12
12
|
PaymentsConfigMixin,
|
13
13
|
get_payments_config,
|
14
14
|
is_payments_enabled,
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
from .constance import (
|
19
|
-
get_django_cfg_payments_constance_fields,
|
20
|
-
PaymentConstanceSettings,
|
15
|
+
is_payments_configured,
|
16
|
+
get_config_summary,
|
17
|
+
reset_payments_config_cache,
|
21
18
|
)
|
22
19
|
|
23
20
|
# Configuration helpers
|
24
21
|
from .helpers import (
|
25
22
|
MiddlewareConfigHelper,
|
26
23
|
CacheConfigHelper,
|
24
|
+
RedisConfigHelper,
|
27
25
|
)
|
28
26
|
|
29
27
|
__all__ = [
|
30
|
-
# Django-cfg integration
|
28
|
+
# Django-cfg integration (BaseCfgAutoModule)
|
29
|
+
'PaymentsConfigManager',
|
31
30
|
'PaymentsConfigMixin',
|
32
31
|
'get_payments_config',
|
33
32
|
'is_payments_enabled',
|
34
|
-
|
35
|
-
|
36
|
-
'
|
37
|
-
'PaymentConstanceSettings',
|
33
|
+
'is_payments_configured',
|
34
|
+
'get_config_summary',
|
35
|
+
'reset_payments_config_cache',
|
38
36
|
|
39
37
|
# Configuration helpers
|
40
38
|
'MiddlewareConfigHelper',
|
41
39
|
'CacheConfigHelper',
|
40
|
+
'RedisConfigHelper',
|
42
41
|
]
|
@@ -136,7 +136,7 @@ class PaymentsConfigManager:
|
|
136
136
|
'rate_limiting_enabled': config.rate_limiting_enabled,
|
137
137
|
'usage_tracking_enabled': config.usage_tracking_enabled,
|
138
138
|
'cache_timeouts': config.cache_timeouts,
|
139
|
-
'
|
139
|
+
'enabled_providers': config.get_enabled_providers(),
|
140
140
|
}
|
141
141
|
except Exception as e:
|
142
142
|
return {
|
@@ -144,6 +144,64 @@ class PaymentsConfigManager:
|
|
144
144
|
'error': str(e),
|
145
145
|
'enabled': False,
|
146
146
|
}
|
147
|
+
|
148
|
+
@classmethod
|
149
|
+
def get_provider_api_config(cls, provider: str) -> dict:
|
150
|
+
"""
|
151
|
+
Get provider-specific API configuration from BaseCfgAutoModule.
|
152
|
+
|
153
|
+
Args:
|
154
|
+
provider: Provider name (e.g., 'nowpayments')
|
155
|
+
|
156
|
+
Returns:
|
157
|
+
Dictionary with provider API configuration
|
158
|
+
"""
|
159
|
+
try:
|
160
|
+
config = cls.get_payments_config()
|
161
|
+
return config.get_provider_api_config(provider)
|
162
|
+
except Exception as e:
|
163
|
+
logger.error(f"Failed to get provider config for {provider}: {e}")
|
164
|
+
return {'enabled': False}
|
165
|
+
|
166
|
+
@classmethod
|
167
|
+
def get_all_provider_configs(cls) -> dict:
|
168
|
+
"""
|
169
|
+
Get all provider configurations for registry initialization.
|
170
|
+
|
171
|
+
Returns:
|
172
|
+
Dictionary with all provider configurations
|
173
|
+
"""
|
174
|
+
try:
|
175
|
+
config = cls.get_payments_config()
|
176
|
+
providers = {}
|
177
|
+
|
178
|
+
# Get all enabled providers
|
179
|
+
for provider_name in config.get_enabled_providers():
|
180
|
+
provider_config = config.get_provider_api_config(provider_name)
|
181
|
+
if provider_config.get('enabled', False):
|
182
|
+
providers[provider_name] = provider_config
|
183
|
+
|
184
|
+
return providers
|
185
|
+
except Exception as e:
|
186
|
+
logger.error(f"Failed to get all provider configs: {e}")
|
187
|
+
return {}
|
188
|
+
|
189
|
+
@classmethod
|
190
|
+
def is_provider_enabled(cls, provider: str) -> bool:
|
191
|
+
"""
|
192
|
+
Check if a specific provider is enabled.
|
193
|
+
|
194
|
+
Args:
|
195
|
+
provider: Provider name
|
196
|
+
|
197
|
+
Returns:
|
198
|
+
True if provider is enabled
|
199
|
+
"""
|
200
|
+
try:
|
201
|
+
config = cls.get_payments_config()
|
202
|
+
return config.is_provider_enabled(provider)
|
203
|
+
except Exception:
|
204
|
+
return False
|
147
205
|
|
148
206
|
|
149
207
|
# Legacy compatibility - keep old interface
|
@@ -18,20 +18,11 @@ class MiddlewareConfigHelper(PaymentsConfigMixin):
|
|
18
18
|
|
19
19
|
@classmethod
|
20
20
|
def get_middleware_config(cls) -> Dict[str, Any]:
|
21
|
-
"""Get middleware configuration
|
21
|
+
"""Get middleware configuration from BaseCfgAutoModule."""
|
22
22
|
config = cls.get_payments_config()
|
23
23
|
|
24
|
-
# Get Constance settings for dynamic config
|
25
|
-
try:
|
26
|
-
from .constance import get_payment_config_service
|
27
|
-
config_service = get_payment_config_service()
|
28
|
-
constance_settings = config_service.get_constance_settings()
|
29
|
-
except Exception as e:
|
30
|
-
logger.warning(f"Failed to load Constance settings: {e}")
|
31
|
-
constance_settings = None
|
32
|
-
|
33
24
|
return {
|
34
|
-
#
|
25
|
+
# All settings from BaseCfgAutoModule (django-cfg)
|
35
26
|
'enabled': config.enabled and config.middleware_enabled,
|
36
27
|
'protected_paths': config.protected_paths,
|
37
28
|
'protected_patterns': config.protected_patterns,
|
@@ -41,8 +32,12 @@ class MiddlewareConfigHelper(PaymentsConfigMixin):
|
|
41
32
|
'track_anonymous_usage': config.track_anonymous_usage,
|
42
33
|
'cache_timeouts': config.cache_timeouts,
|
43
34
|
|
44
|
-
#
|
45
|
-
'
|
35
|
+
# Provider API configurations
|
36
|
+
'enabled_providers': config.get_enabled_providers(),
|
37
|
+
'provider_configs': {
|
38
|
+
provider: config.get_provider_api_config(provider)
|
39
|
+
for provider in config.get_enabled_providers()
|
40
|
+
},
|
46
41
|
}
|
47
42
|
|
48
43
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Generated by Django 5.2.6 on 2025-09-
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-29 06:18
|
2
2
|
|
3
3
|
import django.core.validators
|
4
4
|
import django.db.models.deletion
|
@@ -148,6 +148,18 @@ class Migration(migrations.Migration):
|
|
148
148
|
max_length=50,
|
149
149
|
),
|
150
150
|
),
|
151
|
+
(
|
152
|
+
"usd_rate",
|
153
|
+
models.FloatField(
|
154
|
+
default=1.0, help_text="Current USD exchange rate (1 unit = X USD)"
|
155
|
+
),
|
156
|
+
),
|
157
|
+
(
|
158
|
+
"usd_rate_updated_at",
|
159
|
+
models.DateTimeField(
|
160
|
+
blank=True, help_text="When USD rate was last updated", null=True
|
161
|
+
),
|
162
|
+
),
|
151
163
|
],
|
152
164
|
options={
|
153
165
|
"verbose_name": "Currency",
|
@@ -272,50 +284,12 @@ class Migration(migrations.Migration):
|
|
272
284
|
help_text="Currency code as used by the provider", max_length=20
|
273
285
|
),
|
274
286
|
),
|
275
|
-
(
|
276
|
-
"min_amount",
|
277
|
-
models.DecimalField(
|
278
|
-
blank=True,
|
279
|
-
decimal_places=8,
|
280
|
-
help_text="Minimum payment amount for this currency",
|
281
|
-
max_digits=20,
|
282
|
-
null=True,
|
283
|
-
),
|
284
|
-
),
|
285
|
-
(
|
286
|
-
"max_amount",
|
287
|
-
models.DecimalField(
|
288
|
-
blank=True,
|
289
|
-
decimal_places=8,
|
290
|
-
help_text="Maximum payment amount for this currency",
|
291
|
-
max_digits=20,
|
292
|
-
null=True,
|
293
|
-
),
|
294
|
-
),
|
295
287
|
(
|
296
288
|
"is_enabled",
|
297
289
|
models.BooleanField(
|
298
290
|
default=True, help_text="Whether this currency is enabled for this provider"
|
299
291
|
),
|
300
292
|
),
|
301
|
-
(
|
302
|
-
"fee_percentage",
|
303
|
-
models.DecimalField(
|
304
|
-
decimal_places=4,
|
305
|
-
default=0,
|
306
|
-
help_text="Fee percentage (0.0250 = 2.5%)",
|
307
|
-
max_digits=5,
|
308
|
-
),
|
309
|
-
),
|
310
|
-
(
|
311
|
-
"fixed_fee",
|
312
|
-
models.DecimalField(
|
313
|
-
decimal_places=8,
|
314
|
-
default=0,
|
315
|
-
help_text="Fixed fee amount in this currency",
|
316
|
-
max_digits=20,
|
317
|
-
),
|
318
|
-
),
|
319
293
|
(
|
320
294
|
"currency",
|
321
295
|
models.ForeignKey(
|
@@ -981,7 +955,6 @@ class Migration(migrations.Migration):
|
|
981
955
|
options={
|
982
956
|
"verbose_name": "Universal Payment",
|
983
957
|
"verbose_name_plural": "Universal Payments",
|
984
|
-
"db_table": "payments_universal",
|
985
958
|
"ordering": ["-created_at"],
|
986
959
|
},
|
987
960
|
),
|
@@ -1002,6 +975,14 @@ class Migration(migrations.Migration):
|
|
1002
975
|
validators=[django.core.validators.MinValueValidator(0.0)],
|
1003
976
|
),
|
1004
977
|
),
|
978
|
+
(
|
979
|
+
"reserved_usd",
|
980
|
+
models.FloatField(
|
981
|
+
default=0.0,
|
982
|
+
help_text="Reserved amount in USD (pending transactions)",
|
983
|
+
validators=[django.core.validators.MinValueValidator(0.0)],
|
984
|
+
),
|
985
|
+
),
|
1005
986
|
(
|
1006
987
|
"total_deposited",
|
1007
988
|
models.FloatField(
|
@@ -1209,33 +1190,33 @@ class Migration(migrations.Migration):
|
|
1209
1190
|
),
|
1210
1191
|
migrations.AddIndex(
|
1211
1192
|
model_name="universalpayment",
|
1212
|
-
index=models.Index(fields=["user", "status"], name="
|
1193
|
+
index=models.Index(fields=["user", "status"], name="payments_un_user_id_7f6e79_idx"),
|
1213
1194
|
),
|
1214
1195
|
migrations.AddIndex(
|
1215
1196
|
model_name="universalpayment",
|
1216
1197
|
index=models.Index(
|
1217
|
-
fields=["provider", "status"], name="
|
1198
|
+
fields=["provider", "status"], name="payments_un_provide_982d48_idx"
|
1218
1199
|
),
|
1219
1200
|
),
|
1220
1201
|
migrations.AddIndex(
|
1221
1202
|
model_name="universalpayment",
|
1222
1203
|
index=models.Index(
|
1223
|
-
fields=["status", "created_at"], name="
|
1204
|
+
fields=["status", "created_at"], name="payments_un_status_eba1d1_idx"
|
1224
1205
|
),
|
1225
1206
|
),
|
1226
1207
|
migrations.AddIndex(
|
1227
1208
|
model_name="universalpayment",
|
1228
1209
|
index=models.Index(
|
1229
|
-
fields=["provider_payment_id"], name="
|
1210
|
+
fields=["provider_payment_id"], name="payments_un_provide_8ed72f_idx"
|
1230
1211
|
),
|
1231
1212
|
),
|
1232
1213
|
migrations.AddIndex(
|
1233
1214
|
model_name="universalpayment",
|
1234
|
-
index=models.Index(fields=["transaction_hash"], name="
|
1215
|
+
index=models.Index(fields=["transaction_hash"], name="payments_un_transac_6095d4_idx"),
|
1235
1216
|
),
|
1236
1217
|
migrations.AddIndex(
|
1237
1218
|
model_name="universalpayment",
|
1238
|
-
index=models.Index(fields=["expires_at"], name="
|
1219
|
+
index=models.Index(fields=["expires_at"], name="payments_un_expires_6a9f9d_idx"),
|
1239
1220
|
),
|
1240
1221
|
migrations.AddConstraint(
|
1241
1222
|
model_name="universalpayment",
|
@@ -1265,4 +1246,10 @@ class Migration(migrations.Migration):
|
|
1265
1246
|
condition=models.Q(("balance_usd__gte", 0.0)), name="balance_non_negative_check"
|
1266
1247
|
),
|
1267
1248
|
),
|
1249
|
+
migrations.AddConstraint(
|
1250
|
+
model_name="userbalance",
|
1251
|
+
constraint=models.CheckConstraint(
|
1252
|
+
condition=models.Q(("reserved_usd__gte", 0.0)), name="reserved_non_negative_check"
|
1253
|
+
),
|
1254
|
+
),
|
1268
1255
|
]
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-29 06:23
|
2
|
+
|
3
|
+
from django.db import migrations
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
dependencies = [
|
8
|
+
("payments", "0001_initial"),
|
9
|
+
]
|
10
|
+
|
11
|
+
operations = [
|
12
|
+
migrations.RenameIndex(
|
13
|
+
model_name="universalpayment",
|
14
|
+
new_name="payments_un_user_id_8ce187_idx",
|
15
|
+
old_name="payments_un_user_id_7f6e79_idx",
|
16
|
+
),
|
17
|
+
migrations.RenameIndex(
|
18
|
+
model_name="universalpayment",
|
19
|
+
new_name="payments_un_provide_904e1a_idx",
|
20
|
+
old_name="payments_un_provide_982d48_idx",
|
21
|
+
),
|
22
|
+
migrations.RenameIndex(
|
23
|
+
model_name="universalpayment",
|
24
|
+
new_name="payments_un_status_fd808c_idx",
|
25
|
+
old_name="payments_un_status_eba1d1_idx",
|
26
|
+
),
|
27
|
+
migrations.RenameIndex(
|
28
|
+
model_name="universalpayment",
|
29
|
+
new_name="payments_un_provide_553809_idx",
|
30
|
+
old_name="payments_un_provide_8ed72f_idx",
|
31
|
+
),
|
32
|
+
migrations.RenameIndex(
|
33
|
+
model_name="universalpayment",
|
34
|
+
new_name="payments_un_transac_5a0fe3_idx",
|
35
|
+
old_name="payments_un_transac_6095d4_idx",
|
36
|
+
),
|
37
|
+
migrations.RenameIndex(
|
38
|
+
model_name="universalpayment",
|
39
|
+
new_name="payments_un_expires_3b92ad_idx",
|
40
|
+
old_name="payments_un_expires_6a9f9d_idx",
|
41
|
+
),
|
42
|
+
migrations.AlterModelTable(
|
43
|
+
name="universalpayment",
|
44
|
+
table="payments_universal",
|
45
|
+
),
|
46
|
+
]
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-30 07:52
|
2
|
+
|
3
|
+
from django.db import migrations, models
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
dependencies = [
|
8
|
+
(
|
9
|
+
"payments",
|
10
|
+
"0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more",
|
11
|
+
),
|
12
|
+
]
|
13
|
+
|
14
|
+
operations = [
|
15
|
+
migrations.AddField(
|
16
|
+
model_name="universalpayment",
|
17
|
+
name="status_changed_at",
|
18
|
+
field=models.DateTimeField(
|
19
|
+
blank=True,
|
20
|
+
db_index=True,
|
21
|
+
help_text="When the payment status was last changed",
|
22
|
+
null=True,
|
23
|
+
),
|
24
|
+
),
|
25
|
+
]
|