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.
- 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 +16 -6
- django_cfg/apps/payments/management/commands/currency_stats.py +72 -5
- 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/middleware/api_access.py +35 -34
- django_cfg/apps/payments/migrations/0001_initial.py +1 -1
- django_cfg/apps/payments/models/managers/api_key_managers.py +4 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +5 -0
- django_cfg/apps/payments/models/subscriptions.py +0 -24
- django_cfg/apps/payments/services/cache/__init__.py +1 -1
- django_cfg/apps/payments/services/core/balance_service.py +13 -2
- 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/balance_signals.py +7 -4
- 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/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 +41 -1
- {django_cfg-1.3.3.dist-info → django_cfg-1.3.7.dist-info}/METADATA +1 -1
- {django_cfg-1.3.3.dist-info → django_cfg-1.3.7.dist-info}/RECORD +97 -64
- 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/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.3.dist-info → django_cfg-1.3.7.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.3.dist-info → django_cfg-1.3.7.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.3.dist-info → django_cfg-1.3.7.dist-info}/licenses/LICENSE +0 -0
@@ -128,13 +128,28 @@
|
|
128
128
|
|
129
129
|
/* Card Components */
|
130
130
|
.payment-card {
|
131
|
-
|
131
|
+
background: white;
|
132
|
+
border: 1px solid #e5e7eb;
|
133
|
+
border-radius: 12px;
|
134
|
+
padding: 24px;
|
135
|
+
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
|
132
136
|
transition: all 0.2s ease-in-out;
|
133
137
|
}
|
134
138
|
|
135
139
|
.payment-card:hover {
|
136
|
-
|
137
|
-
transform: translateY(-
|
140
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
141
|
+
transform: translateY(-2px);
|
142
|
+
}
|
143
|
+
|
144
|
+
/* Dark theme cards */
|
145
|
+
.dark .payment-card {
|
146
|
+
background: #1f2937;
|
147
|
+
border-color: #374151;
|
148
|
+
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3);
|
149
|
+
}
|
150
|
+
|
151
|
+
.dark .payment-card:hover {
|
152
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.4);
|
138
153
|
}
|
139
154
|
|
140
155
|
.payment-card-header {
|
@@ -153,29 +168,253 @@
|
|
153
168
|
@apply space-y-3;
|
154
169
|
}
|
155
170
|
|
171
|
+
/* Status Cards */
|
172
|
+
.status-card {
|
173
|
+
background: white;
|
174
|
+
border: 1px solid #e5e7eb;
|
175
|
+
border-radius: 12px;
|
176
|
+
padding: 20px;
|
177
|
+
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
|
178
|
+
transition: all 0.2s ease-in-out;
|
179
|
+
}
|
180
|
+
|
181
|
+
.status-card:hover {
|
182
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
183
|
+
transform: translateY(-1px);
|
184
|
+
}
|
185
|
+
|
186
|
+
.status-card-content {
|
187
|
+
display: flex;
|
188
|
+
align-items: center;
|
189
|
+
gap: 16px;
|
190
|
+
}
|
191
|
+
|
192
|
+
.status-card-icon {
|
193
|
+
width: 48px;
|
194
|
+
height: 48px;
|
195
|
+
border-radius: 12px;
|
196
|
+
display: flex;
|
197
|
+
align-items: center;
|
198
|
+
justify-content: center;
|
199
|
+
font-size: 24px;
|
200
|
+
}
|
201
|
+
|
202
|
+
.status-card-info {
|
203
|
+
flex: 1;
|
204
|
+
}
|
205
|
+
|
206
|
+
.status-card-title {
|
207
|
+
font-size: 14px;
|
208
|
+
font-weight: 500;
|
209
|
+
color: #6b7280;
|
210
|
+
margin-bottom: 4px;
|
211
|
+
}
|
212
|
+
|
213
|
+
.status-card-value {
|
214
|
+
font-size: 28px;
|
215
|
+
font-weight: 700;
|
216
|
+
display: flex;
|
217
|
+
align-items: center;
|
218
|
+
gap: 8px;
|
219
|
+
margin-bottom: 4px;
|
220
|
+
}
|
221
|
+
|
222
|
+
.status-card-description {
|
223
|
+
font-size: 12px;
|
224
|
+
color: #9ca3af;
|
225
|
+
margin: 0;
|
226
|
+
}
|
227
|
+
|
228
|
+
.status-card-action-btn {
|
229
|
+
padding: 8px;
|
230
|
+
border-radius: 8px;
|
231
|
+
color: #6b7280;
|
232
|
+
transition: all 0.2s;
|
233
|
+
}
|
234
|
+
|
235
|
+
.status-card-action-btn:hover {
|
236
|
+
background: #f3f4f6;
|
237
|
+
color: #374151;
|
238
|
+
}
|
239
|
+
|
240
|
+
/* Status Card Color Variants */
|
241
|
+
.status-card-blue .status-card-icon {
|
242
|
+
background: #dbeafe;
|
243
|
+
color: #2563eb;
|
244
|
+
}
|
245
|
+
|
246
|
+
.status-card-blue .status-card-value {
|
247
|
+
color: #2563eb;
|
248
|
+
}
|
249
|
+
|
250
|
+
.status-card-green .status-card-icon {
|
251
|
+
background: #dcfce7;
|
252
|
+
color: #16a34a;
|
253
|
+
}
|
254
|
+
|
255
|
+
.status-card-green .status-card-value {
|
256
|
+
color: #16a34a;
|
257
|
+
}
|
258
|
+
|
259
|
+
.status-card-red .status-card-icon {
|
260
|
+
background: #fee2e2;
|
261
|
+
color: #dc2626;
|
262
|
+
}
|
263
|
+
|
264
|
+
.status-card-red .status-card-value {
|
265
|
+
color: #dc2626;
|
266
|
+
}
|
267
|
+
|
268
|
+
.status-card-yellow .status-card-icon {
|
269
|
+
background: #fef3c7;
|
270
|
+
color: #d97706;
|
271
|
+
}
|
272
|
+
|
273
|
+
.status-card-yellow .status-card-value {
|
274
|
+
color: #d97706;
|
275
|
+
}
|
276
|
+
|
277
|
+
.status-card-purple .status-card-icon {
|
278
|
+
background: #f3e8ff;
|
279
|
+
color: #9333ea;
|
280
|
+
}
|
281
|
+
|
282
|
+
.status-card-purple .status-card-value {
|
283
|
+
color: #9333ea;
|
284
|
+
}
|
285
|
+
|
286
|
+
/* Dark Theme Status Cards */
|
287
|
+
.dark .status-card {
|
288
|
+
background: #1f2937;
|
289
|
+
border-color: #374151;
|
290
|
+
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3);
|
291
|
+
}
|
292
|
+
|
293
|
+
.dark .status-card:hover {
|
294
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.4);
|
295
|
+
}
|
296
|
+
|
297
|
+
.dark .status-card-title {
|
298
|
+
color: #d1d5db;
|
299
|
+
}
|
300
|
+
|
301
|
+
.dark .status-card-description {
|
302
|
+
color: #9ca3af;
|
303
|
+
}
|
304
|
+
|
305
|
+
.dark .status-card-action-btn {
|
306
|
+
color: #9ca3af;
|
307
|
+
}
|
308
|
+
|
309
|
+
.dark .status-card-action-btn:hover {
|
310
|
+
background: #374151;
|
311
|
+
color: #f3f4f6;
|
312
|
+
}
|
313
|
+
|
314
|
+
.dark .status-card-blue .status-card-icon {
|
315
|
+
background: #1e3a8a;
|
316
|
+
color: #60a5fa;
|
317
|
+
}
|
318
|
+
|
319
|
+
.dark .status-card-blue .status-card-value {
|
320
|
+
color: #60a5fa;
|
321
|
+
}
|
322
|
+
|
323
|
+
.dark .status-card-green .status-card-icon {
|
324
|
+
background: #14532d;
|
325
|
+
color: #4ade80;
|
326
|
+
}
|
327
|
+
|
328
|
+
.dark .status-card-green .status-card-value {
|
329
|
+
color: #4ade80;
|
330
|
+
}
|
331
|
+
|
332
|
+
.dark .status-card-red .status-card-icon {
|
333
|
+
background: #7f1d1d;
|
334
|
+
color: #f87171;
|
335
|
+
}
|
336
|
+
|
337
|
+
.dark .status-card-red .status-card-value {
|
338
|
+
color: #f87171;
|
339
|
+
}
|
340
|
+
|
341
|
+
.dark .status-card-yellow .status-card-icon {
|
342
|
+
background: #92400e;
|
343
|
+
color: #fbbf24;
|
344
|
+
}
|
345
|
+
|
346
|
+
.dark .status-card-yellow .status-card-value {
|
347
|
+
color: #fbbf24;
|
348
|
+
}
|
349
|
+
|
350
|
+
.dark .status-card-purple .status-card-icon {
|
351
|
+
background: #581c87;
|
352
|
+
color: #c084fc;
|
353
|
+
}
|
354
|
+
|
355
|
+
.dark .status-card-purple .status-card-value {
|
356
|
+
color: #c084fc;
|
357
|
+
}
|
358
|
+
|
156
359
|
/* Status Badges */
|
157
360
|
.status-badge {
|
158
|
-
|
361
|
+
display: inline-flex;
|
362
|
+
align-items: center;
|
363
|
+
padding: 4px 12px;
|
364
|
+
border-radius: 20px;
|
365
|
+
font-size: 12px;
|
366
|
+
font-weight: 500;
|
159
367
|
}
|
160
368
|
|
161
369
|
.status-badge.success {
|
162
|
-
|
370
|
+
background: #dcfce7;
|
371
|
+
color: #166534;
|
163
372
|
}
|
164
373
|
|
165
374
|
.status-badge.error {
|
166
|
-
|
375
|
+
background: #fee2e2;
|
376
|
+
color: #991b1b;
|
167
377
|
}
|
168
378
|
|
169
379
|
.status-badge.warning {
|
170
|
-
|
380
|
+
background: #fef3c7;
|
381
|
+
color: #92400e;
|
171
382
|
}
|
172
383
|
|
173
384
|
.status-badge.info {
|
174
|
-
|
385
|
+
background: #dbeafe;
|
386
|
+
color: #1d4ed8;
|
175
387
|
}
|
176
388
|
|
177
389
|
.status-badge.pending {
|
178
|
-
|
390
|
+
background: #f3f4f6;
|
391
|
+
color: #374151;
|
392
|
+
}
|
393
|
+
|
394
|
+
/* Dark theme badges */
|
395
|
+
.dark .status-badge.success {
|
396
|
+
background: #14532d;
|
397
|
+
color: #4ade80;
|
398
|
+
}
|
399
|
+
|
400
|
+
.dark .status-badge.error {
|
401
|
+
background: #7f1d1d;
|
402
|
+
color: #f87171;
|
403
|
+
}
|
404
|
+
|
405
|
+
.dark .status-badge.warning {
|
406
|
+
background: #92400e;
|
407
|
+
color: #fbbf24;
|
408
|
+
}
|
409
|
+
|
410
|
+
.dark .status-badge.info {
|
411
|
+
background: #1e3a8a;
|
412
|
+
color: #60a5fa;
|
413
|
+
}
|
414
|
+
|
415
|
+
.dark .status-badge.pending {
|
416
|
+
background: #374151;
|
417
|
+
color: #d1d5db;
|
179
418
|
}
|
180
419
|
|
181
420
|
/* Button Components */
|
@@ -0,0 +1,163 @@
|
|
1
|
+
/**
|
2
|
+
* Ngrok Status Component
|
3
|
+
*
|
4
|
+
* Alpine.js component for displaying and managing ngrok tunnel status.
|
5
|
+
*/
|
6
|
+
|
7
|
+
// Ensure PaymentSystem namespace exists
|
8
|
+
window.PaymentSystem = window.PaymentSystem || {};
|
9
|
+
window.PaymentSystem.Components = window.PaymentSystem.Components || {};
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Ngrok Status Card Component
|
13
|
+
*/
|
14
|
+
window.PaymentSystem.Components.ngrokStatus = function() {
|
15
|
+
return {
|
16
|
+
status: {
|
17
|
+
active: false,
|
18
|
+
public_url: '',
|
19
|
+
webhook_url: '',
|
20
|
+
region: 'us',
|
21
|
+
proto: 'https',
|
22
|
+
error: null
|
23
|
+
},
|
24
|
+
refreshing: false,
|
25
|
+
|
26
|
+
async init() {
|
27
|
+
await this.loadStatus();
|
28
|
+
// Auto-refresh every 30 seconds
|
29
|
+
setInterval(() => this.loadStatus(), 30000);
|
30
|
+
},
|
31
|
+
|
32
|
+
async loadStatus() {
|
33
|
+
try {
|
34
|
+
// Use our health check endpoint instead of direct ngrok API
|
35
|
+
const response = await fetch('/api/payments/webhooks/health/');
|
36
|
+
if (response.ok) {
|
37
|
+
const data = await response.json();
|
38
|
+
const ngrokActive = data.details?.ngrok_available || false;
|
39
|
+
const apiUrl = data.details?.api_base_url || '';
|
40
|
+
|
41
|
+
if (ngrokActive) {
|
42
|
+
this.status = {
|
43
|
+
active: true,
|
44
|
+
public_url: apiUrl,
|
45
|
+
webhook_url: apiUrl + '/api/payments/webhooks/',
|
46
|
+
region: 'auto',
|
47
|
+
proto: apiUrl.startsWith('https') ? 'https' : 'http',
|
48
|
+
error: null
|
49
|
+
};
|
50
|
+
} else {
|
51
|
+
this.status = {
|
52
|
+
active: false,
|
53
|
+
public_url: '',
|
54
|
+
webhook_url: '',
|
55
|
+
region: 'us',
|
56
|
+
proto: 'https',
|
57
|
+
error: 'Ngrok tunnel not active'
|
58
|
+
};
|
59
|
+
}
|
60
|
+
} else {
|
61
|
+
this.status = {
|
62
|
+
active: false,
|
63
|
+
public_url: '',
|
64
|
+
webhook_url: '',
|
65
|
+
region: 'us',
|
66
|
+
proto: 'https',
|
67
|
+
error: 'Health check API not accessible'
|
68
|
+
};
|
69
|
+
}
|
70
|
+
} catch (error) {
|
71
|
+
console.error('Failed to fetch Ngrok status:', error);
|
72
|
+
this.status = {
|
73
|
+
active: false,
|
74
|
+
public_url: '',
|
75
|
+
webhook_url: '',
|
76
|
+
region: 'us',
|
77
|
+
proto: 'https',
|
78
|
+
error: error.message || 'Failed to check ngrok status'
|
79
|
+
};
|
80
|
+
}
|
81
|
+
},
|
82
|
+
|
83
|
+
async refreshStatus() {
|
84
|
+
this.refreshing = true;
|
85
|
+
try {
|
86
|
+
await this.loadStatus();
|
87
|
+
} finally {
|
88
|
+
this.refreshing = false;
|
89
|
+
}
|
90
|
+
},
|
91
|
+
|
92
|
+
async copyUrl() {
|
93
|
+
if (this.status.public_url) {
|
94
|
+
try {
|
95
|
+
await navigator.clipboard.writeText(this.status.public_url);
|
96
|
+
this.$dispatch('show-notification', {
|
97
|
+
type: 'success',
|
98
|
+
message: 'Public URL copied to clipboard'
|
99
|
+
});
|
100
|
+
} catch (error) {
|
101
|
+
console.error('Failed to copy URL:', error);
|
102
|
+
this.$dispatch('show-notification', {
|
103
|
+
type: 'error',
|
104
|
+
message: 'Failed to copy URL to clipboard'
|
105
|
+
});
|
106
|
+
}
|
107
|
+
}
|
108
|
+
},
|
109
|
+
|
110
|
+
async copyWebhookUrl() {
|
111
|
+
if (this.status.webhook_url) {
|
112
|
+
try {
|
113
|
+
await navigator.clipboard.writeText(this.status.webhook_url);
|
114
|
+
this.$dispatch('show-notification', {
|
115
|
+
type: 'success',
|
116
|
+
message: 'Webhook URL copied to clipboard'
|
117
|
+
});
|
118
|
+
} catch (error) {
|
119
|
+
console.error('Failed to copy webhook URL:', error);
|
120
|
+
this.$dispatch('show-notification', {
|
121
|
+
type: 'error',
|
122
|
+
message: 'Failed to copy webhook URL to clipboard'
|
123
|
+
});
|
124
|
+
}
|
125
|
+
}
|
126
|
+
},
|
127
|
+
|
128
|
+
openInBrowser() {
|
129
|
+
if (this.status.public_url) {
|
130
|
+
window.open(this.status.public_url, '_blank');
|
131
|
+
}
|
132
|
+
},
|
133
|
+
|
134
|
+
async startTunnel() {
|
135
|
+
// This would typically call a backend endpoint to start ngrok
|
136
|
+
this.$dispatch('show-notification', {
|
137
|
+
type: 'info',
|
138
|
+
message: 'Starting ngrok tunnel... (This feature requires backend implementation)'
|
139
|
+
});
|
140
|
+
},
|
141
|
+
|
142
|
+
async stopTunnel() {
|
143
|
+
// This would typically call a backend endpoint to stop ngrok
|
144
|
+
this.$dispatch('show-notification', {
|
145
|
+
type: 'info',
|
146
|
+
message: 'Stopping ngrok tunnel... (This feature requires backend implementation)'
|
147
|
+
});
|
148
|
+
}
|
149
|
+
};
|
150
|
+
};
|
151
|
+
|
152
|
+
// Global function for backward compatibility
|
153
|
+
window.ngrokStatus = window.PaymentSystem.Components.ngrokStatus;
|
154
|
+
|
155
|
+
// Also define it directly for immediate availability
|
156
|
+
if (!window.ngrokStatus) {
|
157
|
+
window.ngrokStatus = window.PaymentSystem.Components.ngrokStatus;
|
158
|
+
}
|
159
|
+
|
160
|
+
// Debug: Log that the component is loaded
|
161
|
+
console.log('Ngrok Status component loaded:', typeof window.ngrokStatus);
|
162
|
+
console.log('PaymentSystem namespace:', window.PaymentSystem);
|
163
|
+
console.log('Available functions:', Object.keys(window).filter(key => key.includes('ngrok')));
|
@@ -0,0 +1,39 @@
|
|
1
|
+
"""
|
2
|
+
Admin Interface Serializers for Universal Payment System v2.0.
|
3
|
+
|
4
|
+
DRF serializers for admin dashboard API endpoints.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .webhook_serializers import (
|
8
|
+
WebhookEventSerializer,
|
9
|
+
WebhookEventListSerializer,
|
10
|
+
WebhookStatsSerializer,
|
11
|
+
WebhookActionSerializer,
|
12
|
+
WebhookActionResultSerializer,
|
13
|
+
)
|
14
|
+
|
15
|
+
from .payment_serializers import (
|
16
|
+
AdminUserSerializer,
|
17
|
+
AdminPaymentListSerializer,
|
18
|
+
AdminPaymentDetailSerializer,
|
19
|
+
AdminPaymentCreateSerializer,
|
20
|
+
AdminPaymentUpdateSerializer,
|
21
|
+
AdminPaymentStatsSerializer,
|
22
|
+
)
|
23
|
+
|
24
|
+
__all__ = [
|
25
|
+
# Webhook serializers
|
26
|
+
'WebhookEventSerializer',
|
27
|
+
'WebhookEventListSerializer',
|
28
|
+
'WebhookStatsSerializer',
|
29
|
+
'WebhookActionSerializer',
|
30
|
+
'WebhookActionResultSerializer',
|
31
|
+
|
32
|
+
# Payment serializers
|
33
|
+
'AdminUserSerializer',
|
34
|
+
'AdminPaymentListSerializer',
|
35
|
+
'AdminPaymentDetailSerializer',
|
36
|
+
'AdminPaymentCreateSerializer',
|
37
|
+
'AdminPaymentUpdateSerializer',
|
38
|
+
'AdminPaymentStatsSerializer',
|
39
|
+
]
|
@@ -0,0 +1,149 @@
|
|
1
|
+
"""
|
2
|
+
Payment Serializers for Admin Interface.
|
3
|
+
|
4
|
+
DRF serializers for payment management in admin dashboard.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from rest_framework import serializers
|
8
|
+
from django.contrib.auth import get_user_model
|
9
|
+
from ...models import UniversalPayment
|
10
|
+
|
11
|
+
User = get_user_model()
|
12
|
+
|
13
|
+
|
14
|
+
class AdminUserSerializer(serializers.ModelSerializer):
|
15
|
+
"""
|
16
|
+
Simplified user serializer for admin interface.
|
17
|
+
"""
|
18
|
+
class Meta:
|
19
|
+
model = User
|
20
|
+
fields = ['id', 'username', 'email', 'first_name', 'last_name', 'is_active']
|
21
|
+
read_only_fields = fields
|
22
|
+
|
23
|
+
|
24
|
+
class AdminPaymentListSerializer(serializers.ModelSerializer):
|
25
|
+
"""
|
26
|
+
Serializer for payment list in admin interface.
|
27
|
+
"""
|
28
|
+
user = AdminUserSerializer(read_only=True)
|
29
|
+
status_display = serializers.CharField(source='get_status_display', read_only=True)
|
30
|
+
provider_display = serializers.CharField(source='get_provider_display', read_only=True)
|
31
|
+
age = serializers.SerializerMethodField()
|
32
|
+
|
33
|
+
class Meta:
|
34
|
+
model = UniversalPayment
|
35
|
+
fields = [
|
36
|
+
'id', 'user', 'amount_usd', 'currency_code', 'provider', 'provider_display',
|
37
|
+
'status', 'status_display', 'pay_amount', 'pay_address', 'transaction_hash',
|
38
|
+
'created_at', 'updated_at', 'age', 'description'
|
39
|
+
]
|
40
|
+
read_only_fields = fields
|
41
|
+
|
42
|
+
def get_age(self, obj):
|
43
|
+
"""Get human-readable age of payment."""
|
44
|
+
return obj.age_display
|
45
|
+
|
46
|
+
|
47
|
+
class AdminPaymentDetailSerializer(serializers.ModelSerializer):
|
48
|
+
"""
|
49
|
+
Detailed serializer for individual payment in admin interface.
|
50
|
+
"""
|
51
|
+
user = AdminUserSerializer(read_only=True)
|
52
|
+
status_display = serializers.CharField(source='get_status_display', read_only=True)
|
53
|
+
provider_display = serializers.CharField(source='get_provider_display', read_only=True)
|
54
|
+
age = serializers.SerializerMethodField()
|
55
|
+
|
56
|
+
class Meta:
|
57
|
+
model = UniversalPayment
|
58
|
+
fields = [
|
59
|
+
'id', 'user', 'internal_payment_id', 'amount_usd', 'actual_amount_usd',
|
60
|
+
'fee_amount_usd', 'currency_code', 'provider', 'provider_display',
|
61
|
+
'status', 'status_display', 'pay_amount', 'pay_address', 'payment_url',
|
62
|
+
'transaction_hash', 'confirmations_count', 'security_nonce',
|
63
|
+
'expires_at', 'completed_at', 'description', 'callback_url', 'cancel_url',
|
64
|
+
'provider_data', 'webhook_data', 'created_at', 'updated_at', 'age'
|
65
|
+
]
|
66
|
+
read_only_fields = fields
|
67
|
+
|
68
|
+
def get_age(self, obj):
|
69
|
+
"""Get human-readable age of payment."""
|
70
|
+
return obj.age_display
|
71
|
+
|
72
|
+
|
73
|
+
class AdminPaymentCreateSerializer(serializers.ModelSerializer):
|
74
|
+
"""
|
75
|
+
Serializer for creating payments in admin interface.
|
76
|
+
"""
|
77
|
+
class Meta:
|
78
|
+
model = UniversalPayment
|
79
|
+
fields = [
|
80
|
+
'user', 'amount_usd', 'currency_code', 'provider',
|
81
|
+
'description', 'callback_url', 'cancel_url'
|
82
|
+
]
|
83
|
+
|
84
|
+
def validate_amount_usd(self, value):
|
85
|
+
"""Validate USD amount."""
|
86
|
+
if value <= 0:
|
87
|
+
raise serializers.ValidationError("Amount must be positive")
|
88
|
+
if value > 100000: # Max $100k per payment
|
89
|
+
raise serializers.ValidationError("Amount exceeds maximum limit")
|
90
|
+
return value
|
91
|
+
|
92
|
+
|
93
|
+
class AdminPaymentUpdateSerializer(serializers.ModelSerializer):
|
94
|
+
"""
|
95
|
+
Serializer for updating payments in admin interface.
|
96
|
+
"""
|
97
|
+
class Meta:
|
98
|
+
model = UniversalPayment
|
99
|
+
fields = [
|
100
|
+
'status', 'description', 'callback_url', 'cancel_url',
|
101
|
+
'provider_data', 'webhook_data'
|
102
|
+
]
|
103
|
+
|
104
|
+
def validate_status(self, value):
|
105
|
+
"""Validate status transitions."""
|
106
|
+
if self.instance and self.instance.status == UniversalPayment.PaymentStatus.COMPLETED:
|
107
|
+
if value != UniversalPayment.PaymentStatus.COMPLETED:
|
108
|
+
raise serializers.ValidationError("Cannot change status of completed payment")
|
109
|
+
return value
|
110
|
+
|
111
|
+
|
112
|
+
class AdminPaymentStatsSerializer(serializers.Serializer):
|
113
|
+
"""
|
114
|
+
Serializer for payment statistics in admin interface.
|
115
|
+
"""
|
116
|
+
total_payments = serializers.IntegerField()
|
117
|
+
total_amount_usd = serializers.FloatField()
|
118
|
+
successful_payments = serializers.IntegerField()
|
119
|
+
failed_payments = serializers.IntegerField()
|
120
|
+
pending_payments = serializers.IntegerField()
|
121
|
+
success_rate = serializers.FloatField()
|
122
|
+
|
123
|
+
# Provider breakdown
|
124
|
+
by_provider = serializers.DictField(
|
125
|
+
child=serializers.DictField(),
|
126
|
+
help_text="Statistics by provider"
|
127
|
+
)
|
128
|
+
|
129
|
+
# Currency breakdown
|
130
|
+
by_currency = serializers.DictField(
|
131
|
+
child=serializers.DictField(),
|
132
|
+
help_text="Statistics by currency"
|
133
|
+
)
|
134
|
+
|
135
|
+
# Time-based stats
|
136
|
+
last_24h = serializers.DictField(
|
137
|
+
child=serializers.IntegerField(),
|
138
|
+
help_text="Payments in last 24 hours"
|
139
|
+
)
|
140
|
+
|
141
|
+
last_7d = serializers.DictField(
|
142
|
+
child=serializers.IntegerField(),
|
143
|
+
help_text="Payments in last 7 days"
|
144
|
+
)
|
145
|
+
|
146
|
+
last_30d = serializers.DictField(
|
147
|
+
child=serializers.IntegerField(),
|
148
|
+
help_text="Payments in last 30 days"
|
149
|
+
)
|