django-cfg 1.3.1__py3-none-any.whl → 1.3.5__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_interface/old/payments/base.html +175 -0
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +125 -0
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +113 -0
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +35 -0
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +309 -0
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +303 -0
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +382 -0
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +518 -0
- django_cfg/apps/payments/{static → admin_interface/old/static}/payments/css/components.css +248 -9
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +163 -0
- django_cfg/apps/payments/admin_interface/serializers/__init__.py +39 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +149 -0
- django_cfg/apps/payments/admin_interface/serializers/webhook_serializers.py +114 -0
- django_cfg/apps/payments/admin_interface/templates/payments/base.html +55 -90
- django_cfg/apps/payments/admin_interface/templates/payments/components/dialog.html +81 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/ngrok_help_dialog.html +112 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/ngrok_status.html +175 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +21 -17
- django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +123 -250
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +170 -269
- django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +152 -355
- django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +202 -551
- django_cfg/apps/payments/admin_interface/views/__init__.py +25 -14
- django_cfg/apps/payments/admin_interface/views/api/__init__.py +20 -0
- django_cfg/apps/payments/admin_interface/views/api/payments.py +191 -0
- django_cfg/apps/payments/admin_interface/views/api/stats.py +206 -0
- django_cfg/apps/payments/admin_interface/views/api/users.py +60 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +257 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +70 -0
- django_cfg/apps/payments/admin_interface/views/base.py +114 -0
- django_cfg/apps/payments/admin_interface/views/dashboard.py +60 -0
- django_cfg/apps/payments/admin_interface/views/forms.py +94 -0
- django_cfg/apps/payments/config/helpers.py +2 -2
- django_cfg/apps/payments/management/commands/cleanup_expired_data.py +429 -0
- django_cfg/apps/payments/management/commands/currency_stats.py +443 -0
- django_cfg/apps/payments/management/commands/manage_currencies.py +9 -20
- django_cfg/apps/payments/management/commands/manage_providers.py +5 -5
- django_cfg/apps/payments/management/commands/process_pending_payments.py +357 -0
- django_cfg/apps/payments/management/commands/test_providers.py +434 -0
- django_cfg/apps/payments/middleware/api_access.py +35 -34
- django_cfg/apps/payments/migrations/0001_initial.py +1 -1
- django_cfg/apps/payments/models/balance.py +5 -2
- django_cfg/apps/payments/models/managers/api_key_managers.py +6 -2
- django_cfg/apps/payments/models/managers/balance_managers.py +3 -3
- django_cfg/apps/payments/models/managers/payment_managers.py +5 -0
- django_cfg/apps/payments/models/managers/subscription_managers.py +3 -3
- django_cfg/apps/payments/models/subscriptions.py +0 -24
- django_cfg/apps/payments/services/cache/__init__.py +1 -1
- django_cfg/apps/payments/services/cache_service/__init__.py +143 -0
- django_cfg/apps/payments/services/cache_service/api_key_cache.py +37 -0
- django_cfg/apps/payments/services/cache_service/interfaces.py +32 -0
- django_cfg/apps/payments/services/cache_service/keys.py +49 -0
- django_cfg/apps/payments/services/cache_service/rate_limit_cache.py +47 -0
- django_cfg/apps/payments/services/cache_service/simple_cache.py +101 -0
- django_cfg/apps/payments/services/core/balance_service.py +13 -2
- django_cfg/apps/payments/services/core/payment_service.py +49 -22
- django_cfg/apps/payments/services/integrations/ngrok_service.py +3 -3
- django_cfg/apps/payments/services/providers/registry.py +20 -0
- django_cfg/apps/payments/signals/api_key_signals.py +2 -2
- django_cfg/apps/payments/signals/balance_signals.py +8 -5
- django_cfg/apps/payments/static/payments/js/api-client.js +385 -0
- django_cfg/apps/payments/static/payments/js/ngrok-status.js +58 -0
- django_cfg/apps/payments/static/payments/js/payment-dashboard.js +50 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +175 -0
- django_cfg/apps/payments/static/payments/js/payment-list.js +95 -0
- django_cfg/apps/payments/static/payments/js/webhook-dashboard.js +154 -0
- django_cfg/apps/payments/urls.py +4 -0
- django_cfg/apps/payments/urls_admin.py +37 -18
- django_cfg/apps/payments/views/api/api_keys.py +14 -0
- django_cfg/apps/payments/views/api/base.py +1 -0
- django_cfg/apps/payments/views/api/currencies.py +2 -2
- django_cfg/apps/payments/views/api/payments.py +11 -5
- django_cfg/apps/payments/views/api/subscriptions.py +36 -31
- django_cfg/apps/payments/views/overview/__init__.py +40 -0
- django_cfg/apps/payments/views/overview/serializers.py +205 -0
- django_cfg/apps/payments/views/overview/services.py +439 -0
- django_cfg/apps/payments/views/overview/urls.py +27 -0
- django_cfg/apps/payments/views/overview/views.py +231 -0
- django_cfg/apps/payments/views/serializers/api_keys.py +20 -6
- django_cfg/apps/payments/views/serializers/balances.py +5 -8
- django_cfg/apps/payments/views/serializers/currencies.py +2 -6
- django_cfg/apps/payments/views/serializers/payments.py +37 -32
- django_cfg/apps/payments/views/serializers/subscriptions.py +4 -26
- django_cfg/apps/urls.py +2 -1
- django_cfg/core/config.py +25 -15
- django_cfg/core/generation.py +12 -12
- django_cfg/core/integration/display/startup.py +1 -1
- django_cfg/core/validation.py +4 -4
- django_cfg/management/commands/show_config.py +2 -2
- django_cfg/management/commands/tree.py +1 -3
- django_cfg/middleware/__init__.py +2 -0
- django_cfg/middleware/static_nocache.py +55 -0
- django_cfg/models/payments.py +13 -15
- django_cfg/models/security.py +15 -0
- django_cfg/modules/django_ngrok.py +6 -0
- django_cfg/modules/django_unfold/dashboard.py +1 -3
- django_cfg/utils/smart_defaults.py +51 -5
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/METADATA +1 -1
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/RECORD +111 -69
- django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +0 -38
- django_cfg/apps/payments/admin_interface/views/payment_views.py +0 -259
- django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +0 -37
- django_cfg/apps/payments/services/cache/cache_service.py +0 -235
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/loading_spinner.html +0 -0
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/notification.html +0 -0
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/provider_card.html +0 -0
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/currency_converter.html +0 -0
- /django_cfg/apps/payments/admin_interface/{templates → old}/payments/payment_status.html +0 -0
- /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/css/dashboard.css +0 -0
- /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/js/components.js +0 -0
- /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/js/utils.js +0 -0
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.1.dist-info → django_cfg-1.3.5.dist-info}/licenses/LICENSE +0 -0
@@ -40,9 +40,9 @@ class SubscriptionViewSet(PaymentBaseViewSet):
|
|
40
40
|
|
41
41
|
queryset = Subscription.objects.all()
|
42
42
|
serializer_class = SubscriptionSerializer
|
43
|
-
permission_classes = [permissions.
|
44
|
-
filterset_fields = ['status', 'tier', '
|
45
|
-
search_fields = ['user__username', 'user__email'
|
43
|
+
permission_classes = [permissions.IsAuthenticated] # Allow authenticated users
|
44
|
+
filterset_fields = ['status', 'tier', 'user']
|
45
|
+
search_fields = ['user__username', 'user__email']
|
46
46
|
ordering_fields = ['created_at', 'updated_at', 'expires_at', 'total_requests']
|
47
47
|
|
48
48
|
serializer_classes = {
|
@@ -55,11 +55,17 @@ class SubscriptionViewSet(PaymentBaseViewSet):
|
|
55
55
|
|
56
56
|
def get_queryset(self):
|
57
57
|
"""Optimized queryset with related objects."""
|
58
|
-
|
59
|
-
'user'
|
58
|
+
queryset = super().get_queryset().select_related(
|
59
|
+
'user'
|
60
60
|
).prefetch_related(
|
61
|
-
'
|
61
|
+
'endpoint_groups'
|
62
62
|
)
|
63
|
+
|
64
|
+
# Non-staff users can only see their own subscriptions
|
65
|
+
if not self.request.user.is_staff:
|
66
|
+
queryset = queryset.filter(user=self.request.user)
|
67
|
+
|
68
|
+
return queryset
|
63
69
|
|
64
70
|
@action(detail=True, methods=['post'])
|
65
71
|
def update_status(self, request, pk=None):
|
@@ -161,43 +167,42 @@ class SubscriptionViewSet(PaymentBaseViewSet):
|
|
161
167
|
)
|
162
168
|
|
163
169
|
@action(detail=False, methods=['get'])
|
164
|
-
def
|
170
|
+
def by_tier(self, request):
|
165
171
|
"""
|
166
|
-
Get subscriptions grouped by
|
172
|
+
Get subscriptions grouped by tier.
|
167
173
|
|
168
|
-
GET /api/subscriptions/
|
174
|
+
GET /api/subscriptions/by_tier/
|
169
175
|
"""
|
170
176
|
try:
|
171
177
|
queryset = self.filter_queryset(self.get_queryset())
|
172
178
|
|
173
|
-
|
174
|
-
for
|
175
|
-
|
176
|
-
|
179
|
+
tier_stats = {}
|
180
|
+
for tier_choice in Subscription.SubscriptionTier.choices:
|
181
|
+
tier_code = tier_choice[0]
|
182
|
+
tier_name = tier_choice[1]
|
177
183
|
|
178
|
-
|
179
|
-
tariff_stats[tariff_name] = {
|
180
|
-
'tariff_id': tariff_id,
|
181
|
-
'tariff_name': tariff_name,
|
182
|
-
'total_subscriptions': 0,
|
183
|
-
'active_subscriptions': 0,
|
184
|
-
'total_requests': 0,
|
185
|
-
}
|
184
|
+
tier_subscriptions = queryset.filter(tier=tier_code)
|
186
185
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
186
|
+
tier_stats[tier_code] = {
|
187
|
+
'name': tier_name,
|
188
|
+
'total_subscriptions': tier_subscriptions.count(),
|
189
|
+
'active_subscriptions': tier_subscriptions.filter(
|
190
|
+
status=Subscription.SubscriptionStatus.ACTIVE
|
191
|
+
).count(),
|
192
|
+
'total_requests': tier_subscriptions.aggregate(
|
193
|
+
total=models.Sum('total_requests')
|
194
|
+
)['total'] or 0,
|
195
|
+
}
|
191
196
|
|
192
197
|
return Response({
|
193
|
-
'
|
198
|
+
'tier_stats': tier_stats,
|
194
199
|
'generated_at': timezone.now().isoformat()
|
195
200
|
})
|
196
201
|
|
197
202
|
except Exception as e:
|
198
|
-
logger.error(f"Subscription
|
203
|
+
logger.error(f"Subscription tier stats failed: {e}")
|
199
204
|
return Response(
|
200
|
-
{'error': f'
|
205
|
+
{'error': f'Tier stats failed: {e}'},
|
201
206
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
202
207
|
)
|
203
208
|
|
@@ -212,8 +217,8 @@ class UserSubscriptionViewSet(NestedPaymentViewSet):
|
|
212
217
|
queryset = Subscription.objects.all()
|
213
218
|
serializer_class = SubscriptionSerializer
|
214
219
|
permission_classes = [permissions.IsAuthenticated]
|
215
|
-
filterset_fields = ['status', 'tier'
|
216
|
-
search_fields = [
|
220
|
+
filterset_fields = ['status', 'tier']
|
221
|
+
search_fields = []
|
217
222
|
ordering_fields = ['created_at', 'updated_at', 'expires_at']
|
218
223
|
|
219
224
|
# Nested ViewSet configuration
|
@@ -236,7 +241,7 @@ class UserSubscriptionViewSet(NestedPaymentViewSet):
|
|
236
241
|
if str(self.request.user.id) != str(user_id):
|
237
242
|
return queryset.none()
|
238
243
|
|
239
|
-
return queryset.select_related('
|
244
|
+
return queryset.select_related('user').prefetch_related('endpoint_groups')
|
240
245
|
|
241
246
|
@action(detail=True, methods=['post'])
|
242
247
|
def update_status(self, request, user_pk=None, pk=None):
|
@@ -0,0 +1,40 @@
|
|
1
|
+
"""
|
2
|
+
💰 Payments Overview Dashboard
|
3
|
+
|
4
|
+
Overview dashboard for user payment metrics and analytics.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .views import PaymentsDashboardViewSet
|
8
|
+
from .serializers import (
|
9
|
+
PaymentsDashboardOverviewSerializer,
|
10
|
+
PaymentsMetricsSerializer,
|
11
|
+
BalanceOverviewSerializer,
|
12
|
+
SubscriptionOverviewSerializer,
|
13
|
+
APIKeysOverviewSerializer,
|
14
|
+
PaymentsChartResponseSerializer,
|
15
|
+
)
|
16
|
+
from .services import (
|
17
|
+
PaymentsDashboardMetricsService,
|
18
|
+
PaymentsUsageChartService,
|
19
|
+
RecentPaymentsService,
|
20
|
+
PaymentsAnalyticsService,
|
21
|
+
)
|
22
|
+
|
23
|
+
__all__ = [
|
24
|
+
# Views
|
25
|
+
'PaymentsDashboardViewSet',
|
26
|
+
|
27
|
+
# Serializers
|
28
|
+
'PaymentsDashboardOverviewSerializer',
|
29
|
+
'PaymentsMetricsSerializer',
|
30
|
+
'BalanceOverviewSerializer',
|
31
|
+
'SubscriptionOverviewSerializer',
|
32
|
+
'APIKeysOverviewSerializer',
|
33
|
+
'PaymentsChartResponseSerializer',
|
34
|
+
|
35
|
+
# Services
|
36
|
+
'PaymentsDashboardMetricsService',
|
37
|
+
'PaymentsUsageChartService',
|
38
|
+
'RecentPaymentsService',
|
39
|
+
'PaymentsAnalyticsService',
|
40
|
+
]
|
@@ -0,0 +1,205 @@
|
|
1
|
+
"""
|
2
|
+
💰 Payments Overview Dashboard Serializers
|
3
|
+
|
4
|
+
DRF serializers for payments dashboard data with drf-spectacular integration.
|
5
|
+
"""
|
6
|
+
from rest_framework import serializers
|
7
|
+
from drf_spectacular.utils import extend_schema_field
|
8
|
+
from typing import Dict, Any
|
9
|
+
|
10
|
+
|
11
|
+
class BalanceOverviewSerializer(serializers.Serializer):
|
12
|
+
"""
|
13
|
+
User balance overview metrics
|
14
|
+
"""
|
15
|
+
current_balance = serializers.FloatField(help_text="Current balance in USD")
|
16
|
+
balance_display = serializers.CharField(help_text="Formatted balance display")
|
17
|
+
total_deposited = serializers.FloatField(help_text="Total amount deposited (lifetime)")
|
18
|
+
total_spent = serializers.FloatField(help_text="Total amount spent (lifetime)")
|
19
|
+
last_transaction_at = serializers.DateTimeField(allow_null=True, help_text="Last transaction timestamp")
|
20
|
+
has_transactions = serializers.BooleanField(help_text="Whether user has any transactions")
|
21
|
+
is_empty = serializers.BooleanField(help_text="Whether balance is zero")
|
22
|
+
|
23
|
+
|
24
|
+
class SubscriptionOverviewSerializer(serializers.Serializer):
|
25
|
+
"""
|
26
|
+
Current subscription overview
|
27
|
+
"""
|
28
|
+
tier = serializers.CharField(help_text="Subscription tier")
|
29
|
+
tier_display = serializers.CharField(help_text="Human-readable tier name")
|
30
|
+
status = serializers.CharField(help_text="Subscription status")
|
31
|
+
status_display = serializers.CharField(help_text="Human-readable status")
|
32
|
+
status_color = serializers.CharField(help_text="Color for status display")
|
33
|
+
is_active = serializers.BooleanField(help_text="Whether subscription is active")
|
34
|
+
is_expired = serializers.BooleanField(help_text="Whether subscription is expired")
|
35
|
+
days_remaining = serializers.IntegerField(help_text="Days until expiration")
|
36
|
+
|
37
|
+
# Limits and usage
|
38
|
+
requests_per_hour = serializers.IntegerField(help_text="Hourly request limit")
|
39
|
+
requests_per_day = serializers.IntegerField(help_text="Daily request limit")
|
40
|
+
total_requests = serializers.IntegerField(help_text="Total requests made")
|
41
|
+
usage_percentage = serializers.FloatField(help_text="Usage percentage for current period")
|
42
|
+
|
43
|
+
# Billing
|
44
|
+
monthly_cost_usd = serializers.FloatField(help_text="Monthly cost in USD")
|
45
|
+
cost_display = serializers.CharField(help_text="Formatted cost display")
|
46
|
+
|
47
|
+
# Dates
|
48
|
+
starts_at = serializers.DateTimeField(help_text="Subscription start date")
|
49
|
+
expires_at = serializers.DateTimeField(help_text="Subscription expiration date")
|
50
|
+
last_request_at = serializers.DateTimeField(allow_null=True, help_text="Last API request timestamp")
|
51
|
+
|
52
|
+
# Access
|
53
|
+
endpoint_groups_count = serializers.IntegerField(help_text="Number of accessible endpoint groups")
|
54
|
+
endpoint_groups = serializers.ListField(
|
55
|
+
child=serializers.CharField(),
|
56
|
+
help_text="List of accessible endpoint group names"
|
57
|
+
)
|
58
|
+
|
59
|
+
|
60
|
+
class APIKeysOverviewSerializer(serializers.Serializer):
|
61
|
+
"""
|
62
|
+
API keys overview metrics
|
63
|
+
"""
|
64
|
+
total_keys = serializers.IntegerField(help_text="Total number of API keys")
|
65
|
+
active_keys = serializers.IntegerField(help_text="Number of active API keys")
|
66
|
+
expired_keys = serializers.IntegerField(help_text="Number of expired API keys")
|
67
|
+
total_requests = serializers.IntegerField(help_text="Total requests across all keys")
|
68
|
+
last_used_at = serializers.DateTimeField(allow_null=True, help_text="When any key was last used")
|
69
|
+
|
70
|
+
# Recent keys info
|
71
|
+
most_used_key_name = serializers.CharField(allow_null=True, help_text="Name of most used API key")
|
72
|
+
most_used_key_requests = serializers.IntegerField(help_text="Requests count for most used key")
|
73
|
+
|
74
|
+
# Expiring keys warning
|
75
|
+
expiring_soon_count = serializers.IntegerField(help_text="Number of keys expiring within 7 days")
|
76
|
+
|
77
|
+
|
78
|
+
class PaymentOverviewSerializer(serializers.Serializer):
|
79
|
+
"""
|
80
|
+
Payments overview metrics
|
81
|
+
"""
|
82
|
+
total_payments = serializers.IntegerField(help_text="Total number of payments")
|
83
|
+
completed_payments = serializers.IntegerField(help_text="Number of completed payments")
|
84
|
+
pending_payments = serializers.IntegerField(help_text="Number of pending payments")
|
85
|
+
failed_payments = serializers.IntegerField(help_text="Number of failed payments")
|
86
|
+
|
87
|
+
# Amounts
|
88
|
+
total_amount_usd = serializers.FloatField(help_text="Total payment amount in USD")
|
89
|
+
completed_amount_usd = serializers.FloatField(help_text="Total completed amount in USD")
|
90
|
+
average_payment_usd = serializers.FloatField(help_text="Average payment amount in USD")
|
91
|
+
|
92
|
+
# Success rate
|
93
|
+
success_rate = serializers.FloatField(help_text="Payment success rate percentage")
|
94
|
+
|
95
|
+
# Recent activity
|
96
|
+
last_payment_at = serializers.DateTimeField(allow_null=True, help_text="Last payment timestamp")
|
97
|
+
payments_this_month = serializers.IntegerField(help_text="Number of payments this month")
|
98
|
+
amount_this_month = serializers.FloatField(help_text="Total amount this month")
|
99
|
+
|
100
|
+
# Popular currencies
|
101
|
+
top_currency = serializers.CharField(allow_null=True, help_text="Most used currency")
|
102
|
+
top_currency_count = serializers.IntegerField(help_text="Usage count for top currency")
|
103
|
+
|
104
|
+
|
105
|
+
class PaymentsMetricsSerializer(serializers.Serializer):
|
106
|
+
"""
|
107
|
+
Complete payments dashboard metrics
|
108
|
+
"""
|
109
|
+
balance = BalanceOverviewSerializer(help_text="Balance overview")
|
110
|
+
subscription = SubscriptionOverviewSerializer(allow_null=True, help_text="Subscription overview")
|
111
|
+
api_keys = APIKeysOverviewSerializer(help_text="API keys overview")
|
112
|
+
payments = PaymentOverviewSerializer(help_text="Payments overview")
|
113
|
+
|
114
|
+
|
115
|
+
class RecentPaymentSerializer(serializers.Serializer):
|
116
|
+
"""
|
117
|
+
Recent payment item
|
118
|
+
"""
|
119
|
+
id = serializers.UUIDField(help_text="Payment ID")
|
120
|
+
internal_payment_id = serializers.CharField(help_text="Internal payment ID")
|
121
|
+
amount_usd = serializers.FloatField(help_text="Payment amount in USD")
|
122
|
+
amount_display = serializers.CharField(help_text="Formatted amount display")
|
123
|
+
currency_code = serializers.CharField(help_text="Currency code")
|
124
|
+
status = serializers.CharField(help_text="Payment status")
|
125
|
+
status_display = serializers.CharField(help_text="Human-readable status")
|
126
|
+
status_color = serializers.CharField(help_text="Color for status display")
|
127
|
+
provider = serializers.CharField(help_text="Payment provider")
|
128
|
+
created_at = serializers.DateTimeField(help_text="Payment creation timestamp")
|
129
|
+
completed_at = serializers.DateTimeField(allow_null=True, help_text="Payment completion timestamp")
|
130
|
+
|
131
|
+
# Status flags
|
132
|
+
is_pending = serializers.BooleanField(help_text="Whether payment is pending")
|
133
|
+
is_completed = serializers.BooleanField(help_text="Whether payment is completed")
|
134
|
+
is_failed = serializers.BooleanField(help_text="Whether payment failed")
|
135
|
+
|
136
|
+
|
137
|
+
class RecentTransactionSerializer(serializers.Serializer):
|
138
|
+
"""
|
139
|
+
Recent transaction item
|
140
|
+
"""
|
141
|
+
id = serializers.UUIDField(help_text="Transaction ID")
|
142
|
+
transaction_type = serializers.CharField(help_text="Transaction type")
|
143
|
+
amount_usd = serializers.FloatField(help_text="Transaction amount in USD")
|
144
|
+
amount_display = serializers.CharField(help_text="Formatted amount display")
|
145
|
+
balance_after = serializers.FloatField(help_text="Balance after transaction")
|
146
|
+
description = serializers.CharField(help_text="Transaction description")
|
147
|
+
created_at = serializers.DateTimeField(help_text="Transaction timestamp")
|
148
|
+
payment_id = serializers.CharField(allow_null=True, help_text="Related payment ID")
|
149
|
+
|
150
|
+
# Type info
|
151
|
+
is_credit = serializers.BooleanField(help_text="Whether this is a credit transaction")
|
152
|
+
is_debit = serializers.BooleanField(help_text="Whether this is a debit transaction")
|
153
|
+
type_color = serializers.CharField(help_text="Color for transaction type display")
|
154
|
+
|
155
|
+
|
156
|
+
class ChartDataPointSerializer(serializers.Serializer):
|
157
|
+
"""
|
158
|
+
Chart data point for payments analytics
|
159
|
+
"""
|
160
|
+
x = serializers.CharField(help_text="X-axis value (date)")
|
161
|
+
y = serializers.FloatField(help_text="Y-axis value (amount or count)")
|
162
|
+
|
163
|
+
|
164
|
+
class ChartSeriesSerializer(serializers.Serializer):
|
165
|
+
"""
|
166
|
+
Chart series data for payments visualization
|
167
|
+
"""
|
168
|
+
name = serializers.CharField(help_text="Series name")
|
169
|
+
data = ChartDataPointSerializer(many=True, help_text="Data points")
|
170
|
+
color = serializers.CharField(help_text="Series color")
|
171
|
+
|
172
|
+
|
173
|
+
class PaymentsChartResponseSerializer(serializers.Serializer):
|
174
|
+
"""
|
175
|
+
Complete chart response for payments analytics
|
176
|
+
"""
|
177
|
+
series = ChartSeriesSerializer(many=True, help_text="Chart series data")
|
178
|
+
period = serializers.CharField(help_text="Time period")
|
179
|
+
total_amount = serializers.FloatField(help_text="Total amount for period")
|
180
|
+
total_payments = serializers.IntegerField(help_text="Total payments for period")
|
181
|
+
success_rate = serializers.FloatField(help_text="Success rate for period")
|
182
|
+
|
183
|
+
|
184
|
+
class PaymentsDashboardOverviewSerializer(serializers.Serializer):
|
185
|
+
"""
|
186
|
+
Complete payments dashboard overview response
|
187
|
+
"""
|
188
|
+
metrics = PaymentsMetricsSerializer(help_text="Dashboard metrics")
|
189
|
+
recent_payments = RecentPaymentSerializer(many=True, help_text="Recent payments")
|
190
|
+
recent_transactions = RecentTransactionSerializer(many=True, help_text="Recent transactions")
|
191
|
+
chart_data = PaymentsChartResponseSerializer(help_text="Chart data for analytics")
|
192
|
+
|
193
|
+
|
194
|
+
class TimePeriodSerializer(serializers.Serializer):
|
195
|
+
"""
|
196
|
+
Time period filter for charts and analytics
|
197
|
+
"""
|
198
|
+
PERIOD_CHOICES = [
|
199
|
+
('7d', 'Last 7 days'),
|
200
|
+
('30d', 'Last 30 days'),
|
201
|
+
('90d', 'Last 90 days'),
|
202
|
+
('1y', 'Last year'),
|
203
|
+
]
|
204
|
+
|
205
|
+
period = serializers.ChoiceField(choices=PERIOD_CHOICES, default='30d')
|