django-cfg 1.3.3__py3-none-any.whl → 1.3.7__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 (100) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/payments/admin_interface/old/payments/base.html +175 -0
  3. django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +125 -0
  4. django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +113 -0
  5. django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +35 -0
  6. django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +309 -0
  7. django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +303 -0
  8. django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +382 -0
  9. django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +518 -0
  10. django_cfg/apps/payments/{static → admin_interface/old/static}/payments/css/components.css +248 -9
  11. django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +163 -0
  12. django_cfg/apps/payments/admin_interface/serializers/__init__.py +39 -0
  13. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +149 -0
  14. django_cfg/apps/payments/admin_interface/serializers/webhook_serializers.py +114 -0
  15. django_cfg/apps/payments/admin_interface/templates/payments/base.html +55 -90
  16. django_cfg/apps/payments/admin_interface/templates/payments/components/dialog.html +81 -0
  17. django_cfg/apps/payments/admin_interface/templates/payments/components/ngrok_help_dialog.html +112 -0
  18. django_cfg/apps/payments/admin_interface/templates/payments/components/ngrok_status.html +175 -0
  19. django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +21 -17
  20. django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +123 -250
  21. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +170 -269
  22. django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +152 -355
  23. django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +202 -551
  24. django_cfg/apps/payments/admin_interface/views/__init__.py +25 -14
  25. django_cfg/apps/payments/admin_interface/views/api/__init__.py +20 -0
  26. django_cfg/apps/payments/admin_interface/views/api/payments.py +191 -0
  27. django_cfg/apps/payments/admin_interface/views/api/stats.py +206 -0
  28. django_cfg/apps/payments/admin_interface/views/api/users.py +60 -0
  29. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +257 -0
  30. django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +70 -0
  31. django_cfg/apps/payments/admin_interface/views/base.py +114 -0
  32. django_cfg/apps/payments/admin_interface/views/dashboard.py +60 -0
  33. django_cfg/apps/payments/admin_interface/views/forms.py +94 -0
  34. django_cfg/apps/payments/config/helpers.py +2 -2
  35. django_cfg/apps/payments/management/commands/cleanup_expired_data.py +16 -6
  36. django_cfg/apps/payments/management/commands/currency_stats.py +72 -5
  37. django_cfg/apps/payments/management/commands/manage_currencies.py +9 -20
  38. django_cfg/apps/payments/management/commands/manage_providers.py +5 -5
  39. django_cfg/apps/payments/middleware/api_access.py +35 -34
  40. django_cfg/apps/payments/migrations/0001_initial.py +1 -1
  41. django_cfg/apps/payments/models/managers/api_key_managers.py +4 -0
  42. django_cfg/apps/payments/models/managers/payment_managers.py +5 -0
  43. django_cfg/apps/payments/models/subscriptions.py +0 -24
  44. django_cfg/apps/payments/services/cache/__init__.py +1 -1
  45. django_cfg/apps/payments/services/core/balance_service.py +13 -2
  46. django_cfg/apps/payments/services/integrations/ngrok_service.py +3 -3
  47. django_cfg/apps/payments/services/providers/registry.py +20 -0
  48. django_cfg/apps/payments/signals/balance_signals.py +7 -4
  49. django_cfg/apps/payments/static/payments/js/api-client.js +385 -0
  50. django_cfg/apps/payments/static/payments/js/ngrok-status.js +58 -0
  51. django_cfg/apps/payments/static/payments/js/payment-dashboard.js +50 -0
  52. django_cfg/apps/payments/static/payments/js/payment-form.js +175 -0
  53. django_cfg/apps/payments/static/payments/js/payment-list.js +95 -0
  54. django_cfg/apps/payments/static/payments/js/webhook-dashboard.js +154 -0
  55. django_cfg/apps/payments/urls.py +4 -0
  56. django_cfg/apps/payments/urls_admin.py +37 -18
  57. django_cfg/apps/payments/views/api/api_keys.py +14 -0
  58. django_cfg/apps/payments/views/api/base.py +1 -0
  59. django_cfg/apps/payments/views/api/currencies.py +2 -2
  60. django_cfg/apps/payments/views/api/payments.py +11 -5
  61. django_cfg/apps/payments/views/api/subscriptions.py +36 -31
  62. django_cfg/apps/payments/views/overview/__init__.py +40 -0
  63. django_cfg/apps/payments/views/overview/serializers.py +205 -0
  64. django_cfg/apps/payments/views/overview/services.py +439 -0
  65. django_cfg/apps/payments/views/overview/urls.py +27 -0
  66. django_cfg/apps/payments/views/overview/views.py +231 -0
  67. django_cfg/apps/payments/views/serializers/api_keys.py +20 -6
  68. django_cfg/apps/payments/views/serializers/balances.py +5 -8
  69. django_cfg/apps/payments/views/serializers/currencies.py +2 -6
  70. django_cfg/apps/payments/views/serializers/payments.py +37 -32
  71. django_cfg/apps/payments/views/serializers/subscriptions.py +4 -26
  72. django_cfg/core/config.py +25 -15
  73. django_cfg/core/generation.py +12 -12
  74. django_cfg/core/integration/display/startup.py +1 -1
  75. django_cfg/core/validation.py +4 -4
  76. django_cfg/management/commands/show_config.py +2 -2
  77. django_cfg/management/commands/tree.py +1 -3
  78. django_cfg/middleware/__init__.py +2 -0
  79. django_cfg/middleware/static_nocache.py +55 -0
  80. django_cfg/models/payments.py +13 -15
  81. django_cfg/models/security.py +15 -0
  82. django_cfg/modules/django_ngrok.py +6 -0
  83. django_cfg/modules/django_unfold/dashboard.py +1 -3
  84. django_cfg/utils/smart_defaults.py +41 -1
  85. {django_cfg-1.3.3.dist-info → django_cfg-1.3.7.dist-info}/METADATA +1 -1
  86. {django_cfg-1.3.3.dist-info → django_cfg-1.3.7.dist-info}/RECORD +97 -64
  87. django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +0 -38
  88. django_cfg/apps/payments/admin_interface/views/payment_views.py +0 -259
  89. django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +0 -37
  90. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/loading_spinner.html +0 -0
  91. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/notification.html +0 -0
  92. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/provider_card.html +0 -0
  93. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/currency_converter.html +0 -0
  94. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/payment_status.html +0 -0
  95. /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/css/dashboard.css +0 -0
  96. /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/js/components.js +0 -0
  97. /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/js/utils.js +0 -0
  98. {django_cfg-1.3.3.dist-info → django_cfg-1.3.7.dist-info}/WHEEL +0 -0
  99. {django_cfg-1.3.3.dist-info → django_cfg-1.3.7.dist-info}/entry_points.txt +0 -0
  100. {django_cfg-1.3.3.dist-info → django_cfg-1.3.7.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,257 @@
1
+ """
2
+ Admin Webhook ViewSets.
3
+
4
+ DRF ViewSets for webhook management in admin interface.
5
+ Requires admin permissions.
6
+ """
7
+
8
+ from rest_framework import viewsets, status
9
+ from rest_framework.decorators import action
10
+ from rest_framework.response import Response
11
+ from rest_framework.generics import ListAPIView
12
+ from django_filters.rest_framework import DjangoFilterBackend
13
+ from rest_framework.filters import SearchFilter, OrderingFilter
14
+ from django.utils import timezone
15
+ from django.db import models
16
+ from datetime import datetime, timedelta
17
+
18
+ from django_cfg.apps.payments.admin_interface.views.base import AdminBaseViewSet, AdminReadOnlyViewSet
19
+ from django_cfg.apps.payments.admin_interface.serializers import (
20
+ WebhookEventSerializer,
21
+ WebhookEventListSerializer,
22
+ WebhookStatsSerializer,
23
+ WebhookActionSerializer,
24
+ WebhookActionResultSerializer,
25
+ )
26
+ from django_cfg.apps.payments.services.core.webhook_service import WebhookService
27
+ from django_cfg.apps.payments.models import UniversalPayment
28
+ from django_cfg.modules.django_logger import get_logger
29
+
30
+ logger = get_logger("admin_webhook_api")
31
+
32
+
33
+ class AdminWebhookViewSet(AdminReadOnlyViewSet):
34
+ """
35
+ Admin ViewSet for webhook configuration management.
36
+
37
+ Read-only view for webhook configurations and provider info.
38
+ Requires admin permissions.
39
+ """
40
+
41
+ # No model - this is for webhook configuration data
42
+ serializer_class = WebhookStatsSerializer
43
+
44
+ def list(self, request):
45
+ """List webhook providers and configurations."""
46
+ # Mock webhook provider data - replace with real configuration
47
+ providers_data = [
48
+ {
49
+ 'name': 'nowpayments',
50
+ 'display_name': 'NowPayments',
51
+ 'enabled': True,
52
+ 'webhook_url': 'https://api.nowpayments.io/v1/webhooks',
53
+ 'supported_events': ['payment.created', 'payment.completed', 'payment.failed'],
54
+ 'last_ping': timezone.now() - timedelta(minutes=5),
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'
65
+ }
66
+ ]
67
+
68
+ serializer = self.get_serializer(providers_data, many=True)
69
+ return Response(serializer.data)
70
+
71
+ @action(detail=False, methods=['get'])
72
+ def stats(self, request):
73
+ """Get webhook statistics."""
74
+ # Get real payment data for stats
75
+ total_payments = UniversalPayment.objects.count()
76
+ recent_payments = UniversalPayment.objects.filter(
77
+ created_at__gte=timezone.now() - timedelta(days=7)
78
+ ).count()
79
+
80
+ # Mock webhook stats based on real payment data
81
+ stats_data = {
82
+ 'total_events': total_payments * 2, # Assume 2 events per payment on average
83
+ 'successful_events': int(total_payments * 1.8), # 90% success rate
84
+ 'failed_events': int(total_payments * 0.2), # 10% failure rate
85
+ 'success_rate': 90.0,
86
+ 'recent_events': recent_payments * 2,
87
+ 'providers': {
88
+ 'nowpayments': {
89
+ 'total': int(total_payments * 0.7),
90
+ 'successful': int(total_payments * 0.65),
91
+ 'failed': int(total_payments * 0.05),
92
+ 'success_rate': 92.8
93
+ },
94
+ 'stripe': {
95
+ 'total': int(total_payments * 0.3),
96
+ 'successful': int(total_payments * 0.28),
97
+ 'failed': int(total_payments * 0.02),
98
+ 'success_rate': 93.3
99
+ }
100
+ },
101
+ 'events_by_type': {
102
+ 'payment.created': int(total_payments * 1.0),
103
+ 'payment.completed': int(total_payments * 0.8),
104
+ 'payment.failed': int(total_payments * 0.2),
105
+ },
106
+ 'recent_activity': [
107
+ {
108
+ 'timestamp': timezone.now() - timedelta(minutes=i*5),
109
+ 'event_type': 'payment.created' if i % 3 == 0 else 'payment.completed',
110
+ 'provider': 'nowpayments' if i % 2 == 0 else 'stripe',
111
+ 'status': 'success' if i % 4 != 0 else 'failed'
112
+ }
113
+ for i in range(10)
114
+ ]
115
+ }
116
+
117
+ serializer = self.get_serializer(stats_data)
118
+ return Response(serializer.data)
119
+
120
+
121
+ class AdminWebhookEventViewSet(AdminReadOnlyViewSet):
122
+ """
123
+ Admin ViewSet for webhook events management.
124
+
125
+ Provides listing, filtering, and actions for webhook events.
126
+ Requires admin permissions.
127
+ """
128
+
129
+ # No model - using mock data for now
130
+ serializer_class = WebhookEventListSerializer
131
+ filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
132
+ filterset_fields = ['event_type', 'status', 'provider']
133
+ search_fields = ['event_type', 'webhook_url']
134
+ ordering_fields = ['created_at', 'event_type', 'status']
135
+ ordering = ['-created_at']
136
+
137
+ def get_queryset(self):
138
+ """Get webhook events queryset."""
139
+ # For now, return empty queryset since we're using mock data
140
+ # In real implementation, this would return WebhookEvent.objects.all()
141
+ return UniversalPayment.objects.none()
142
+
143
+ def list(self, request):
144
+ """List webhook events with filtering and pagination."""
145
+ # Get filter parameters
146
+ event_type = request.query_params.get('event_type')
147
+ status_filter = request.query_params.get('status')
148
+ provider = request.query_params.get('provider')
149
+
150
+ # Get real payment data to generate realistic mock events
151
+ payments = UniversalPayment.objects.all()[:50] # Limit for performance
152
+
153
+ # Generate mock webhook events based on real payments
154
+ events = []
155
+ for i, payment in enumerate(payments):
156
+ # Create multiple events per payment
157
+ event_types = ['payment.created', 'payment.completed'] if payment.status == 'completed' else ['payment.created']
158
+
159
+ for event_type_name in event_types:
160
+ event = {
161
+ 'id': f"evt_{payment.id}_{event_type_name.split('.')[1]}",
162
+ 'event_type': event_type_name,
163
+ 'webhook_url': f'https://example.com/webhook/{payment.id}',
164
+ 'status': 'success' if i % 5 != 0 else 'failed',
165
+ 'provider': 'nowpayments' if i % 2 == 0 else 'stripe',
166
+ 'created_at': payment.created_at,
167
+ 'response_code': 200 if i % 5 != 0 else 500,
168
+ 'response_time': f"{50 + (i % 200)}ms",
169
+ 'attempts': 1 if i % 5 != 0 else 3,
170
+ 'payload': {
171
+ 'payment_id': str(payment.id),
172
+ 'amount': str(payment.amount),
173
+ 'currency': payment.currency,
174
+ 'status': payment.status,
175
+ 'timestamp': payment.created_at.isoformat()
176
+ }
177
+ }
178
+
179
+ # Apply filters
180
+ if event_type and event['event_type'] != event_type:
181
+ continue
182
+ if status_filter and event['status'] != status_filter:
183
+ continue
184
+ if provider and event['provider'] != provider:
185
+ continue
186
+
187
+ events.append(event)
188
+
189
+ # Sort by created_at descending
190
+ events.sort(key=lambda x: x['created_at'], reverse=True)
191
+
192
+ # Pagination
193
+ page_size = 20
194
+ page = int(request.query_params.get('page', 1))
195
+ start = (page - 1) * page_size
196
+ end = start + page_size
197
+ paginated_events = events[start:end]
198
+
199
+ response_data = {
200
+ 'events': paginated_events,
201
+ 'total': len(events),
202
+ 'page': page,
203
+ 'per_page': page_size,
204
+ 'has_next': end < len(events),
205
+ 'has_previous': page > 1
206
+ }
207
+
208
+ serializer = self.get_serializer(response_data)
209
+ return Response(serializer.data)
210
+
211
+ @action(detail=True, methods=['post'])
212
+ def retry(self, request, pk=None):
213
+ """Retry a failed webhook event."""
214
+ # Mock retry logic
215
+ result_data = {
216
+ 'success': True,
217
+ 'message': f'Webhook event {pk} retry initiated',
218
+ 'event_id': pk,
219
+ 'retry_count': 2,
220
+ 'next_retry': timezone.now() + timedelta(minutes=5)
221
+ }
222
+
223
+ serializer = WebhookActionResultSerializer(result_data)
224
+ logger.info(f"Webhook event {pk} retry initiated by admin {request.user.id}")
225
+ return Response(serializer.data)
226
+
227
+ @action(detail=False, methods=['post'])
228
+ def clear_all(self, request):
229
+ """Clear all webhook events."""
230
+ # Mock clear all logic
231
+ result_data = {
232
+ 'success': True,
233
+ 'message': 'All webhook events cleared',
234
+ 'cleared_count': 150, # Mock count
235
+ }
236
+
237
+ serializer = WebhookActionResultSerializer(result_data)
238
+ logger.info(f"All webhook events cleared by admin {request.user.id}")
239
+ return Response(serializer.data)
240
+
241
+ @action(detail=False, methods=['post'])
242
+ def retry_failed(self, request):
243
+ """Retry all failed webhook events."""
244
+ # Mock retry failed logic
245
+ # In real implementation:
246
+ # failed_events = WebhookEvent.objects.filter(status='failed')
247
+ # results = [retry_webhook_event(event) for event in failed_events]
248
+
249
+ result_data = {
250
+ 'success': True,
251
+ 'message': 'All failed webhook events retry initiated',
252
+ 'processed_count': 0, # Mock count
253
+ }
254
+
255
+ serializer = WebhookActionResultSerializer(result_data)
256
+ logger.info(f"All failed webhook events retry initiated by admin {request.user.id}")
257
+ return Response(serializer.data)
@@ -0,0 +1,70 @@
1
+ """
2
+ Public Webhook ViewSets.
3
+
4
+ DRF ViewSets for public webhook functionality.
5
+ No authentication required.
6
+ """
7
+
8
+ from rest_framework import viewsets, status
9
+ from rest_framework.decorators import action
10
+ from rest_framework.response import Response
11
+ from rest_framework.permissions import AllowAny
12
+ from django.utils import timezone
13
+
14
+ from django_cfg.apps.payments.admin_interface.serializers import WebhookStatsSerializer
15
+ from django_cfg.modules.django_logger import get_logger
16
+
17
+ logger = get_logger("webhook_public_api")
18
+
19
+
20
+ class WebhookTestViewSet(viewsets.ViewSet):
21
+ """
22
+ Public ViewSet for webhook testing functionality.
23
+
24
+ Allows testing webhook endpoints without admin permissions.
25
+ Perfect for development and integration testing.
26
+ """
27
+
28
+ permission_classes = [AllowAny] # Explicitly allow any user
29
+ serializer_class = WebhookStatsSerializer # For schema generation
30
+
31
+ @action(detail=False, methods=['post'])
32
+ def test(self, request):
33
+ """
34
+ Test webhook endpoint.
35
+
36
+ Sends a test webhook to the specified URL with the given event type.
37
+ Useful for developers to test their webhook implementations.
38
+ """
39
+ webhook_url = request.data.get('webhook_url')
40
+ event_type = request.data.get('event_type')
41
+
42
+ if not webhook_url or not event_type:
43
+ return Response({
44
+ 'success': False,
45
+ 'error': 'webhook_url and event_type are required'
46
+ }, status=status.HTTP_400_BAD_REQUEST)
47
+
48
+ # TODO: In real implementation, send actual HTTP request to webhook_url
49
+ # For now, return mock success response
50
+
51
+ logger.info(f"Test webhook sent to {webhook_url} with event type {event_type}")
52
+
53
+ return Response({
54
+ 'success': True,
55
+ 'message': f'Test webhook sent to {webhook_url} with event type {event_type}',
56
+ 'webhook_url': webhook_url,
57
+ 'event_type': event_type,
58
+ 'timestamp': timezone.now().isoformat(),
59
+ 'test_payload': {
60
+ 'event': event_type,
61
+ 'data': {
62
+ 'id': 'test_payment_123',
63
+ 'amount': '100.00',
64
+ 'currency': 'USD',
65
+ 'status': 'completed',
66
+ 'created_at': timezone.now().isoformat()
67
+ },
68
+ 'timestamp': timezone.now().isoformat()
69
+ }
70
+ })
@@ -0,0 +1,114 @@
1
+ """
2
+ Base ViewSet classes for Admin Interface API.
3
+
4
+ Common functionality for all admin interface ViewSets.
5
+ """
6
+
7
+ from rest_framework import viewsets, permissions, status
8
+ from rest_framework.decorators import action
9
+ from rest_framework.response import Response
10
+ from rest_framework.permissions import IsAdminUser
11
+ from django_filters.rest_framework import DjangoFilterBackend
12
+ from rest_framework.filters import SearchFilter, OrderingFilter
13
+ from django.contrib.admin.views.decorators import staff_member_required
14
+ from django.utils.decorators import method_decorator
15
+ from django.utils import timezone
16
+ from datetime import timedelta
17
+
18
+
19
+ from django_cfg.modules.django_logger import get_logger
20
+
21
+ logger = get_logger("admin_api")
22
+
23
+
24
+ class AdminBaseViewSet(viewsets.ModelViewSet):
25
+ """
26
+ Base ViewSet for admin interface with staff permissions.
27
+
28
+ Provides standard CRUD operations with admin-only access.
29
+ """
30
+
31
+ permission_classes = [IsAdminUser]
32
+ filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
33
+ ordering = ['-created_at']
34
+
35
+ # Serializer classes mapping for different actions
36
+ serializer_classes = {}
37
+
38
+ def get_queryset(self):
39
+ """
40
+ Optimized queryset for admin interface.
41
+
42
+ Override in subclasses to add specific optimizations.
43
+ """
44
+ queryset = super().get_queryset()
45
+
46
+ # Add common optimizations for admin
47
+ if hasattr(self.queryset.model, 'user'):
48
+ queryset = queryset.select_related('user')
49
+
50
+ return queryset
51
+
52
+ def get_serializer_class(self):
53
+ """
54
+ Dynamic serializer selection based on action.
55
+ """
56
+ serializer_classes = getattr(self, 'serializer_classes', {})
57
+ return serializer_classes.get(self.action, self.serializer_class)
58
+
59
+ def get_serializer_context(self):
60
+ """Enhanced context for admin serializers."""
61
+ context = super().get_serializer_context()
62
+ context.update({
63
+ 'is_admin': True,
64
+ 'admin_user': self.request.user,
65
+ })
66
+ return context
67
+
68
+ @action(detail=False, methods=['get'])
69
+ def stats(self, request):
70
+ """Get statistics for this resource."""
71
+ queryset = self.get_queryset()
72
+ stats = {
73
+ 'total': queryset.count(),
74
+ 'recent': queryset.filter(
75
+ created_at__gte=timezone.now() - timedelta(days=7)
76
+ ).count(),
77
+ }
78
+ return Response(stats)
79
+
80
+
81
+ class AdminReadOnlyViewSet(viewsets.ReadOnlyModelViewSet):
82
+ """
83
+ Read-only ViewSet for admin interface.
84
+
85
+ For resources that should only be viewed, not modified.
86
+ """
87
+
88
+ permission_classes = [IsAdminUser]
89
+ filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
90
+ ordering = ['-created_at']
91
+
92
+ def get_serializer_context(self):
93
+ """Enhanced context for admin serializers."""
94
+ context = super().get_serializer_context()
95
+ context.update({
96
+ 'is_admin': True,
97
+ 'admin_user': self.request.user,
98
+ })
99
+ return context
100
+
101
+
102
+ class AdminTemplateViewMixin:
103
+ """
104
+ Mixin for template views requiring staff access.
105
+ """
106
+
107
+ def get_context_data(self, **kwargs):
108
+ """Add admin-specific context."""
109
+ context = super().get_context_data(**kwargs)
110
+ context.update({
111
+ 'is_admin_interface': True,
112
+ 'admin_user': self.request.user,
113
+ })
114
+ return context
@@ -0,0 +1,60 @@
1
+ """
2
+ Admin Dashboard Template Views.
3
+
4
+ Django template views for admin dashboard interface.
5
+ """
6
+
7
+ from django.views.generic import TemplateView
8
+ from django.contrib.auth.mixins import LoginRequiredMixin
9
+ from django.contrib.admin.views.decorators import staff_member_required
10
+ from django.utils.decorators import method_decorator
11
+
12
+ from .base import AdminTemplateViewMixin
13
+
14
+
15
+ @method_decorator(staff_member_required, name='dispatch')
16
+ class PaymentDashboardView(AdminTemplateViewMixin, LoginRequiredMixin, TemplateView):
17
+ """
18
+ Main admin dashboard view.
19
+
20
+ Displays overview of payments, webhooks, and system statistics.
21
+ """
22
+
23
+ template_name = 'payments/payment_dashboard.html'
24
+
25
+ def get_context_data(self, **kwargs):
26
+ """Add dashboard context data."""
27
+ context = super().get_context_data(**kwargs)
28
+
29
+ context.update({
30
+ 'page_title': 'Payment Dashboard',
31
+ 'page_subtitle': 'Overview of payment system activity',
32
+ 'show_stats': True,
33
+ 'auto_refresh': True,
34
+ })
35
+
36
+ return context
37
+
38
+
39
+ @method_decorator(staff_member_required, name='dispatch')
40
+ class WebhookDashboardView(AdminTemplateViewMixin, LoginRequiredMixin, TemplateView):
41
+ """
42
+ Webhook dashboard view.
43
+
44
+ Displays webhook events, provider status, and ngrok configuration.
45
+ """
46
+
47
+ template_name = 'payments/webhook_dashboard.html'
48
+
49
+ def get_context_data(self, **kwargs):
50
+ """Add webhook dashboard context data."""
51
+ context = super().get_context_data(**kwargs)
52
+
53
+ context.update({
54
+ 'page_title': 'Webhook Dashboard',
55
+ 'page_subtitle': 'Monitor and test webhook endpoints',
56
+ 'show_ngrok_status': True,
57
+ 'auto_refresh': True,
58
+ })
59
+
60
+ return context
@@ -0,0 +1,94 @@
1
+ """
2
+ Admin Form Template Views.
3
+
4
+ Django template views for payment forms and detail pages.
5
+ """
6
+
7
+ from django.views.generic import TemplateView, DetailView
8
+ from django.contrib.auth.mixins import LoginRequiredMixin
9
+ from django.contrib.admin.views.decorators import staff_member_required
10
+ from django.utils.decorators import method_decorator
11
+ from django.shortcuts import get_object_or_404
12
+
13
+ from .base import AdminTemplateViewMixin
14
+ from django_cfg.apps.payments.models import UniversalPayment
15
+
16
+
17
+ @method_decorator(staff_member_required, name='dispatch')
18
+ class PaymentFormView(AdminTemplateViewMixin, LoginRequiredMixin, TemplateView):
19
+ """
20
+ Payment creation form view.
21
+
22
+ Displays form for creating new payments with provider selection.
23
+ """
24
+
25
+ template_name = 'payments/payment_form.html'
26
+
27
+ def get_context_data(self, **kwargs):
28
+ """Add form context data."""
29
+ context = super().get_context_data(**kwargs)
30
+
31
+ context.update({
32
+ 'page_title': 'Create Payment',
33
+ 'page_subtitle': 'Process a payment through the universal payment system',
34
+ 'form_mode': 'create',
35
+ })
36
+
37
+ return context
38
+
39
+
40
+ @method_decorator(staff_member_required, name='dispatch')
41
+ class PaymentDetailView(AdminTemplateViewMixin, LoginRequiredMixin, DetailView):
42
+ """
43
+ Payment detail view.
44
+
45
+ Displays detailed information about a specific payment.
46
+ """
47
+
48
+ model = UniversalPayment
49
+ template_name = 'payments/payment_detail.html'
50
+ context_object_name = 'payment'
51
+
52
+ def get_queryset(self):
53
+ """Optimized queryset with related objects."""
54
+ return UniversalPayment.objects.select_related('user')
55
+
56
+ def get_context_data(self, **kwargs):
57
+ """Add detail context data."""
58
+ context = super().get_context_data(**kwargs)
59
+
60
+ payment = self.get_object()
61
+
62
+ context.update({
63
+ 'page_title': f'Payment {payment.internal_payment_id or payment.id}',
64
+ 'page_subtitle': f'Payment details and transaction history',
65
+ 'show_actions': True,
66
+ 'can_cancel': payment.status in ['pending', 'confirming'],
67
+ 'can_refund': payment.status == 'completed',
68
+ })
69
+
70
+ return context
71
+
72
+
73
+ @method_decorator(staff_member_required, name='dispatch')
74
+ class PaymentListView(AdminTemplateViewMixin, LoginRequiredMixin, TemplateView):
75
+ """
76
+ Payment list view.
77
+
78
+ Displays paginated list of payments with filtering options.
79
+ """
80
+
81
+ template_name = 'payments/payment_list.html'
82
+
83
+ def get_context_data(self, **kwargs):
84
+ """Add list context data."""
85
+ context = super().get_context_data(**kwargs)
86
+
87
+ context.update({
88
+ 'page_title': 'Payment List',
89
+ 'page_subtitle': 'Manage and monitor all payments',
90
+ 'show_filters': True,
91
+ 'show_bulk_actions': True,
92
+ })
93
+
94
+ return context
@@ -33,8 +33,8 @@ class MiddlewareConfigHelper(PaymentsConfigMixin):
33
33
  return {
34
34
  # Static settings from django-cfg
35
35
  'enabled': config.enabled and config.middleware_enabled,
36
- 'api_prefixes': config.api_prefixes,
37
- 'exempt_paths': config.exempt_paths,
36
+ 'protected_paths': config.protected_paths,
37
+ 'protected_patterns': config.protected_patterns,
38
38
  'rate_limiting_enabled': config.rate_limiting_enabled,
39
39
  'default_rate_limits': config.default_rate_limits,
40
40
  'usage_tracking_enabled': config.usage_tracking_enabled,
@@ -15,7 +15,7 @@ from django.core.cache import cache
15
15
 
16
16
  from django_cfg.modules.django_logger import get_logger
17
17
  from django_cfg.apps.payments.models import UniversalPayment, APIKey, Transaction
18
- from django_cfg.apps.payments.services.cache.cache_service import get_cache_service
18
+ from django_cfg.apps.payments.services.cache_service import get_cache_service
19
19
 
20
20
  logger = get_logger("cleanup_expired_data")
21
21
 
@@ -68,6 +68,12 @@ class Command(BaseCommand):
68
68
  help='Clean up all types of expired data'
69
69
  )
70
70
 
71
+ parser.add_argument(
72
+ '--payments-only',
73
+ action='store_true',
74
+ help='Clean up only expired payments'
75
+ )
76
+
71
77
  parser.add_argument(
72
78
  '--dry-run',
73
79
  action='store_true',
@@ -107,16 +113,20 @@ class Command(BaseCommand):
107
113
 
108
114
  # Determine what to clean
109
115
  clean_all = options['all']
116
+ payments_only = options['payments_only']
110
117
 
111
- if clean_all or not any([options['api_keys'], options['cache']]):
118
+ if payments_only:
119
+ # Only clean payments
120
+ self.cleanup_expired_payments()
121
+ elif clean_all or not any([options['api_keys'], options['cache']]):
112
122
  # Default: clean payments and transactions
113
123
  self.cleanup_expired_payments()
114
124
  self.cleanup_old_transactions()
115
125
 
116
- if clean_all or options['api_keys']:
126
+ if not payments_only and (clean_all or options['api_keys']):
117
127
  self.cleanup_expired_api_keys()
118
128
 
119
- if clean_all or options['cache']:
129
+ if not payments_only and (clean_all or options['cache']):
120
130
  self.cleanup_stale_cache()
121
131
 
122
132
  self.show_summary()
@@ -217,8 +227,8 @@ class Command(BaseCommand):
217
227
  old_transactions = Transaction.objects.filter(
218
228
  created_at__lt=cutoff_date
219
229
  ).exclude(
220
- # Keep transactions for completed payments
221
- payment__status='completed'
230
+ # Keep transactions with payment references (important transactions)
231
+ payment_id__isnull=False
222
232
  )
223
233
 
224
234
  total_count = old_transactions.count()