django-cfg 1.3.3__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.
Files changed (101) 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/apps/urls.py +2 -1
  73. django_cfg/core/config.py +25 -15
  74. django_cfg/core/generation.py +12 -12
  75. django_cfg/core/integration/display/startup.py +1 -1
  76. django_cfg/core/validation.py +4 -4
  77. django_cfg/management/commands/show_config.py +2 -2
  78. django_cfg/management/commands/tree.py +1 -3
  79. django_cfg/middleware/__init__.py +2 -0
  80. django_cfg/middleware/static_nocache.py +55 -0
  81. django_cfg/models/payments.py +13 -15
  82. django_cfg/models/security.py +15 -0
  83. django_cfg/modules/django_ngrok.py +6 -0
  84. django_cfg/modules/django_unfold/dashboard.py +1 -3
  85. django_cfg/utils/smart_defaults.py +41 -1
  86. {django_cfg-1.3.3.dist-info → django_cfg-1.3.5.dist-info}/METADATA +1 -1
  87. {django_cfg-1.3.3.dist-info → django_cfg-1.3.5.dist-info}/RECORD +98 -65
  88. django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +0 -38
  89. django_cfg/apps/payments/admin_interface/views/payment_views.py +0 -259
  90. django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +0 -37
  91. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/loading_spinner.html +0 -0
  92. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/notification.html +0 -0
  93. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/components/provider_card.html +0 -0
  94. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/currency_converter.html +0 -0
  95. /django_cfg/apps/payments/admin_interface/{templates → old}/payments/payment_status.html +0 -0
  96. /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/css/dashboard.css +0 -0
  97. /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/js/components.js +0 -0
  98. /django_cfg/apps/payments/{static → admin_interface/old/static}/payments/js/utils.js +0 -0
  99. {django_cfg-1.3.3.dist-info → django_cfg-1.3.5.dist-info}/WHEEL +0 -0
  100. {django_cfg-1.3.3.dist-info → django_cfg-1.3.5.dist-info}/entry_points.txt +0 -0
  101. {django_cfg-1.3.3.dist-info → django_cfg-1.3.5.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,385 @@
1
+ /**
2
+ * Payment API Client
3
+ * Provides convenient methods for API calls with automatic JSON handling
4
+ */
5
+ class PaymentAPIClient {
6
+ constructor() {
7
+ this.baseURL = '/api/payments';
8
+ this.adminURL = '/cfg/admin/django_cfg_payments/admin';
9
+ }
10
+
11
+ // Helper method to get CSRF token
12
+ getCSRFToken() {
13
+ const token = document.querySelector('[name=csrfmiddlewaretoken]');
14
+ return token ? token.value : '';
15
+ }
16
+
17
+ // Generic request method
18
+ async request(url, options = {}) {
19
+ const config = {
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ 'X-CSRFToken': this.getCSRFToken(),
23
+ ...options.headers
24
+ },
25
+ ...options
26
+ };
27
+
28
+ try {
29
+ const response = await fetch(url, config);
30
+
31
+ if (!response.ok) {
32
+ const error = await response.json().catch(() => ({ message: 'Request failed' }));
33
+ throw new Error(error.message || `HTTP ${response.status}`);
34
+ }
35
+
36
+ return await response.json();
37
+ } catch (error) {
38
+ console.error('API Request failed:', error);
39
+ throw error;
40
+ }
41
+ }
42
+
43
+ // GET request
44
+ async get(url, params = {}) {
45
+ const urlWithParams = new URL(url, window.location.origin);
46
+ Object.entries(params).forEach(([key, value]) => {
47
+ if (value !== null && value !== undefined && value !== '') {
48
+ urlWithParams.searchParams.append(key, value);
49
+ }
50
+ });
51
+
52
+ return this.request(urlWithParams.toString());
53
+ }
54
+
55
+ // POST request
56
+ async post(url, data = {}) {
57
+ return this.request(url, {
58
+ method: 'POST',
59
+ body: JSON.stringify(data)
60
+ });
61
+ }
62
+
63
+ // PUT request
64
+ async put(url, data = {}) {
65
+ return this.request(url, {
66
+ method: 'PUT',
67
+ body: JSON.stringify(data)
68
+ });
69
+ }
70
+
71
+ // DELETE request
72
+ async delete(url) {
73
+ return this.request(url, {
74
+ method: 'DELETE'
75
+ });
76
+ }
77
+
78
+ // PAYMENTS API
79
+ payments = {
80
+ // Get all payments
81
+ list: (params = {}) => this.get(`${this.baseURL}/payments/`, params),
82
+
83
+ // Get payment by ID
84
+ get: (id) => this.get(`${this.baseURL}/payments/${id}/`),
85
+
86
+ // Create payment
87
+ create: (data) => this.post(`${this.baseURL}/payments/create/`, data),
88
+
89
+ // Get payment status
90
+ status: (id) => this.get(`${this.baseURL}/payments/status/${id}/`),
91
+
92
+ // Check payment status
93
+ checkStatus: (id) => this.post(`${this.baseURL}/payments/${id}/check_status/`),
94
+
95
+ // Cancel payment
96
+ cancel: (id) => this.post(`${this.baseURL}/payments/${id}/cancel/`),
97
+
98
+ // Get payment stats
99
+ stats: () => this.get(`${this.baseURL}/payments/stats/`),
100
+
101
+ // Get payment analytics
102
+ analytics: (params = {}) => this.get(`${this.baseURL}/payments/analytics/`, params),
103
+
104
+ // Get payments by provider
105
+ byProvider: (provider) => this.get(`${this.baseURL}/payments/by_provider/`, { provider })
106
+ };
107
+
108
+ // WEBHOOKS API
109
+ webhooks = {
110
+ // Get webhook stats
111
+ stats: () => this.get(`${this.baseURL}/webhooks/stats/`),
112
+
113
+ // Get supported providers
114
+ providers: () => this.get(`${this.baseURL}/webhooks/providers/`),
115
+
116
+ // Health check
117
+ health: () => this.get(`${this.baseURL}/webhooks/health/`)
118
+ };
119
+
120
+ // CURRENCIES API
121
+ currencies = {
122
+ // Get all currencies
123
+ list: () => this.get(`${this.baseURL}/currencies/`),
124
+
125
+ // Get currency by ID
126
+ get: (id) => this.get(`${this.baseURL}/currencies/${id}/`),
127
+
128
+ // Get supported currencies
129
+ supported: (params = {}) => this.get(`${this.baseURL}/currencies/supported/`, params),
130
+
131
+ // Get currencies by provider
132
+ byProvider: (provider) => this.get(`${this.baseURL}/currencies/supported/`, { provider }),
133
+
134
+ // Get exchange rates
135
+ rates: (params = {}) => this.get(`${this.baseURL}/currencies/rates/`, params),
136
+
137
+ // Convert currency
138
+ convert: (from, to, amount) => this.post(`${this.baseURL}/currencies/convert/`, { from, to, amount }),
139
+
140
+ // Get provider-specific currency configurations
141
+ providerConfigs: (provider) => this.get(`${this.baseURL}/provider-currencies/`, { provider }),
142
+
143
+ // Get currencies grouped by provider
144
+ byProviderGrouped: () => this.get(`${this.baseURL}/provider-currencies/by_provider/`)
145
+ };
146
+
147
+ // BALANCES API
148
+ balances = {
149
+ // Get all balances
150
+ list: (params = {}) => this.get(`${this.baseURL}/balances/`, params),
151
+
152
+ // Get balance by ID
153
+ get: (id) => this.get(`${this.baseURL}/balances/${id}/`),
154
+
155
+ // Top up balance
156
+ topup: (id, amount, currency) => this.post(`${this.baseURL}/balances/${id}/topup/`, { amount, currency }),
157
+
158
+ // Withdraw from balance
159
+ withdraw: (id, amount, currency) => this.post(`${this.baseURL}/balances/${id}/withdraw/`, { amount, currency })
160
+ };
161
+
162
+ // TRANSACTIONS API
163
+ transactions = {
164
+ // Get all transactions
165
+ list: (params = {}) => this.get(`${this.baseURL}/transactions/`, params),
166
+
167
+ // Get transaction by ID
168
+ get: (id) => this.get(`${this.baseURL}/transactions/${id}/`),
169
+
170
+ // Get recent transactions
171
+ recent: (limit = 10) => this.get(`${this.baseURL}/transactions/recent/`, { limit }),
172
+
173
+ // Get transactions by type
174
+ byType: (type) => this.get(`${this.baseURL}/transactions/by_type/`, { type }),
175
+
176
+ // Get transaction stats
177
+ stats: () => this.get(`${this.baseURL}/transactions/stats/`)
178
+ };
179
+
180
+ // API KEYS API
181
+ apiKeys = {
182
+ // Get all API keys
183
+ list: () => this.get(`${this.baseURL}/api-keys/`),
184
+
185
+ // Get API key by ID
186
+ get: (id) => this.get(`${this.baseURL}/api-keys/${id}/`),
187
+
188
+ // Generate new API key
189
+ generate: (data) => this.post(`${this.baseURL}/api-keys/generate/`, data),
190
+
191
+ // Revoke API key
192
+ revoke: (id) => this.post(`${this.baseURL}/api-keys/${id}/revoke/`),
193
+
194
+ // Get API key stats
195
+ stats: () => this.get(`${this.baseURL}/api-keys/stats/`)
196
+ };
197
+
198
+ // DASHBOARD API
199
+ dashboard = {
200
+ // Get dashboard overview
201
+ overview: () => this.get(`${this.baseURL}/overview/dashboard/overview/`),
202
+
203
+ // Get dashboard metrics
204
+ metrics: () => this.get(`${this.baseURL}/overview/dashboard/metrics/`),
205
+
206
+ // Get chart data
207
+ chartData: (period = '7d') => this.get(`${this.baseURL}/overview/dashboard/chart_data/`, { period }),
208
+
209
+ // Get recent payments
210
+ recentPayments: (limit = 5) => this.get(`${this.baseURL}/overview/dashboard/recent_payments/`, { limit }),
211
+
212
+ // Get recent transactions
213
+ recentTransactions: (limit = 5) => this.get(`${this.baseURL}/overview/dashboard/recent_transactions/`, { limit }),
214
+
215
+ // Get payment analytics
216
+ paymentAnalytics: () => this.get(`${this.baseURL}/overview/dashboard/payment_analytics/`),
217
+
218
+ // Get balance overview
219
+ balanceOverview: () => this.get(`${this.baseURL}/overview/dashboard/balance_overview/`),
220
+
221
+ // Get subscription overview
222
+ subscriptionOverview: () => this.get(`${this.baseURL}/overview/dashboard/subscription_overview/`),
223
+
224
+ // Get API keys overview
225
+ apiKeysOverview: () => this.get(`${this.baseURL}/overview/dashboard/api_keys_overview/`)
226
+ };
227
+
228
+ // NGROK API (custom endpoints)
229
+ ngrok = {
230
+ // Get ngrok status from webhook health endpoint
231
+ status: async () => {
232
+ try {
233
+ const response = await this.get('/api/payments/webhooks/health/');
234
+ const ngrokActive = response.details?.ngrok_available || false;
235
+ const apiUrl = response.details?.api_base_url || '';
236
+
237
+ if (ngrokActive) {
238
+ return {
239
+ active: true,
240
+ public_url: apiUrl,
241
+ webhook_url: apiUrl + '/api/payments/webhooks/',
242
+ region: 'auto',
243
+ proto: apiUrl.startsWith('https') ? 'https' : 'http',
244
+ error: null
245
+ };
246
+ } else {
247
+ return {
248
+ active: false,
249
+ public_url: '',
250
+ webhook_url: '',
251
+ region: 'us',
252
+ proto: 'https',
253
+ error: 'Ngrok tunnel not active'
254
+ };
255
+ }
256
+ } catch (error) {
257
+ return {
258
+ active: false,
259
+ public_url: '',
260
+ webhook_url: '',
261
+ region: 'us',
262
+ proto: 'https',
263
+ error: error.message || 'Health check API not accessible'
264
+ };
265
+ }
266
+ },
267
+
268
+ // Start ngrok tunnel (placeholder - not implemented)
269
+ start: () => this.post(`${this.adminURL}/ngrok/start/`),
270
+
271
+ // Stop ngrok tunnel (placeholder - not implemented)
272
+ stop: () => this.post(`${this.adminURL}/ngrok/stop/`)
273
+ };
274
+
275
+ // ADMIN API ENDPOINTS (DRF nested router structure)
276
+ admin = {
277
+ // Payments API
278
+ payments: {
279
+ list: (params = {}) => this.get(`${this.adminURL}/api/payments/`, params),
280
+ get: (id) => this.get(`${this.adminURL}/api/payments/${id}/`),
281
+ create: (data) => this.post(`${this.adminURL}/api/payments/`, data),
282
+ update: (id, data) => this.patch(`${this.adminURL}/api/payments/${id}/`, data),
283
+ delete: (id) => this.delete(`${this.adminURL}/api/payments/${id}/`),
284
+ cancel: (id) => this.post(`${this.adminURL}/api/payments/${id}/cancel/`),
285
+ refund: (id) => this.post(`${this.adminURL}/api/payments/${id}/refund/`),
286
+ stats: () => this.get(`${this.adminURL}/api/payments/stats/`)
287
+ },
288
+
289
+ // Webhooks API
290
+ webhooks: {
291
+ list: () => this.get(`${this.adminURL}/api/webhooks/`),
292
+ stats: () => this.get(`${this.adminURL}/api/webhooks/stats/`),
293
+
294
+ // Nested webhook events
295
+ events: {
296
+ list: (webhookId = 1, params = {}) => this.get(`${this.adminURL}/api/webhooks/${webhookId}/events/`, params),
297
+ retry: (webhookId, eventId) => this.post(`${this.adminURL}/api/webhooks/${webhookId}/events/${eventId}/retry/`),
298
+ clearAll: (webhookId) => this.post(`${this.adminURL}/api/webhooks/${webhookId}/events/clear_all/`),
299
+ retryFailed: (webhookId) => this.post(`${this.adminURL}/api/webhooks/${webhookId}/events/retry_failed/`)
300
+ }
301
+ },
302
+
303
+ // Webhook test method
304
+ webhookTest: {
305
+ send: (url, eventType) => this.post(`${this.adminURL}/api/webhooks/test/`, {
306
+ webhook_url: url,
307
+ event_type: eventType
308
+ })
309
+ },
310
+
311
+ // Stats API
312
+ stats: {
313
+ overview: () => this.get(`${this.adminURL}/api/stats/`),
314
+ payments: () => this.get(`${this.adminURL}/api/stats/payments/`),
315
+ webhooks: () => this.get(`${this.adminURL}/api/stats/webhooks/`),
316
+ system: () => this.get(`${this.adminURL}/api/stats/system/`)
317
+ },
318
+
319
+ // Users API
320
+ users: {
321
+ list: (params = {}) => this.get(`${this.adminURL}/api/users/`, params),
322
+ get: (id) => this.get(`${this.adminURL}/api/users/${id}/`),
323
+ search: (query) => this.get(`${this.adminURL}/api/users/`, { q: query })
324
+ }
325
+ };
326
+
327
+
328
+ // Utility methods
329
+ utils = {
330
+ // Format currency
331
+ formatCurrency: (amount, currency = 'USD') => {
332
+ return new Intl.NumberFormat('en-US', {
333
+ style: 'currency',
334
+ currency: currency
335
+ }).format(amount);
336
+ },
337
+
338
+ // Format date
339
+ formatDate: (dateString) => {
340
+ return new Date(dateString).toLocaleDateString('en-US', {
341
+ year: 'numeric',
342
+ month: 'short',
343
+ day: 'numeric',
344
+ hour: '2-digit',
345
+ minute: '2-digit'
346
+ });
347
+ },
348
+
349
+ // Show notification (simple implementation)
350
+ showNotification: (message, type = 'info') => {
351
+ const notification = document.createElement('div');
352
+ notification.className = `fixed top-4 right-4 px-4 py-2 rounded-md shadow-lg z-50 ${
353
+ type === 'success' ? 'bg-green-500 text-white' :
354
+ type === 'error' ? 'bg-red-500 text-white' :
355
+ type === 'warning' ? 'bg-yellow-500 text-white' :
356
+ 'bg-blue-500 text-white'
357
+ }`;
358
+ notification.textContent = message;
359
+ document.body.appendChild(notification);
360
+
361
+ setTimeout(() => {
362
+ notification.remove();
363
+ }, 3000);
364
+ },
365
+
366
+ // Copy to clipboard
367
+ copyToClipboard: async (text) => {
368
+ try {
369
+ await navigator.clipboard.writeText(text);
370
+ PaymentAPI.utils.showNotification('Copied to clipboard!', 'success');
371
+ } catch (error) {
372
+ console.error('Failed to copy:', error);
373
+ PaymentAPI.utils.showNotification('Failed to copy', 'error');
374
+ }
375
+ }
376
+ };
377
+ }
378
+
379
+ // Create global instance
380
+ window.PaymentAPI = new PaymentAPIClient();
381
+
382
+ // Export for modules
383
+ if (typeof module !== 'undefined' && module.exports) {
384
+ module.exports = PaymentAPIClient;
385
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Ngrok Status Component
3
+ * Handles ngrok tunnel status monitoring and control
4
+ */
5
+ function ngrokStatus() {
6
+ return {
7
+ loading: false,
8
+ status: {
9
+ active: false,
10
+ public_url: '',
11
+ webhook_url: '',
12
+ error: null,
13
+ region: 'us',
14
+ proto: 'https'
15
+ },
16
+
17
+ async init() {
18
+ await this.refreshStatus();
19
+ // Auto-refresh every 10 seconds
20
+ setInterval(() => this.refreshStatus(), 10000);
21
+ },
22
+
23
+ async refreshStatus() {
24
+ this.loading = true;
25
+ try {
26
+ const data = await PaymentAPI.ngrok.status();
27
+ this.status = { ...this.status, ...data };
28
+ } catch (error) {
29
+ console.error('Failed to fetch ngrok status:', error);
30
+ this.status.active = false;
31
+ this.status.error = error.message || 'Connection failed';
32
+ } finally {
33
+ this.loading = false;
34
+ }
35
+ },
36
+
37
+
38
+
39
+ copyUrl() {
40
+ if (this.status.public_url) {
41
+ PaymentAPI.utils.copyToClipboard(this.status.public_url);
42
+ }
43
+ },
44
+
45
+ copyWebhookUrl() {
46
+ if (this.status.webhook_url) {
47
+ PaymentAPI.utils.copyToClipboard(this.status.webhook_url);
48
+ }
49
+ },
50
+
51
+ openTunnel() {
52
+ if (this.status.public_url) {
53
+ window.open(this.status.public_url, '_blank');
54
+ }
55
+ },
56
+
57
+ };
58
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Payment Dashboard Component
3
+ * Handles dashboard data loading and display
4
+ */
5
+ function paymentDashboard() {
6
+ return {
7
+ loading: false,
8
+ stats: {
9
+ total: 0,
10
+ successful: 0,
11
+ pending: 0,
12
+ failed: 0
13
+ },
14
+ recentPayments: [],
15
+ recentActivity: [
16
+ { id: 1, message: 'Payment created', time: '2 minutes ago' },
17
+ { id: 2, message: 'Webhook received', time: '5 minutes ago' },
18
+ { id: 3, message: 'Payment completed', time: '10 minutes ago' }
19
+ ],
20
+
21
+ async init() {
22
+ await this.loadDashboardData();
23
+ // Auto-refresh every 60 seconds
24
+ setInterval(() => this.loadDashboardData(), 60000);
25
+ },
26
+
27
+ async loadDashboardData() {
28
+ this.loading = true;
29
+ try {
30
+ // Load dashboard data using API client
31
+ const [overview, recentPayments] = await Promise.all([
32
+ PaymentAPI.dashboard.overview(),
33
+ PaymentAPI.dashboard.recentPayments(5)
34
+ ]);
35
+
36
+ this.stats = overview.stats || this.stats;
37
+ this.recentPayments = recentPayments || [];
38
+ } catch (error) {
39
+ console.error('Failed to load dashboard data:', error);
40
+ PaymentAPI.utils.showNotification('Failed to load dashboard data', 'error');
41
+ } finally {
42
+ this.loading = false;
43
+ }
44
+ },
45
+
46
+ async refreshDashboard() {
47
+ await this.loadDashboardData();
48
+ }
49
+ };
50
+ }
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Payment Form Component
3
+ * Handles payment creation form functionality with real provider currencies
4
+ */
5
+ function paymentForm() {
6
+ return {
7
+ loading: false,
8
+ loadingCurrencies: false,
9
+ form: {
10
+ user: '',
11
+ amount_usd: '',
12
+ currency_code: '',
13
+ provider: 'nowpayments',
14
+ description: '',
15
+ callback_url: '',
16
+ cancel_url: ''
17
+ },
18
+ currencies: [],
19
+ allCurrencies: [],
20
+ providers: [
21
+ { value: 'nowpayments', name: 'NowPayments', display_name: 'NowPayments' }
22
+ ],
23
+ conversionResult: null,
24
+ users: [],
25
+
26
+ async init() {
27
+ await this.loadInitialData();
28
+ },
29
+
30
+ async loadInitialData() {
31
+ this.loading = true;
32
+ try {
33
+ // Load all currencies and provider-specific currencies
34
+ await Promise.all([
35
+ this.loadAllCurrencies(),
36
+ this.loadProviderCurrencies(),
37
+ this.loadUsers()
38
+ ]);
39
+ } catch (error) {
40
+ console.error('Failed to load initial data:', error);
41
+ PaymentAPI.utils.showNotification('Failed to load form data', 'error');
42
+ } finally {
43
+ this.loading = false;
44
+ }
45
+ },
46
+
47
+ async loadAllCurrencies() {
48
+ try {
49
+ const data = await PaymentAPI.currencies.supported();
50
+ this.allCurrencies = data.currencies || [];
51
+ } catch (error) {
52
+ console.error('Failed to load currencies:', error);
53
+ }
54
+ },
55
+
56
+ async loadProviderCurrencies() {
57
+ if (!this.form.provider) return;
58
+
59
+ this.loadingCurrencies = true;
60
+ try {
61
+ const data = await PaymentAPI.currencies.providerConfigs(this.form.provider);
62
+ this.currencies = data.results || data.currencies || [];
63
+
64
+ // Transform provider currency data for display
65
+ this.currencies = this.currencies.map(pc => ({
66
+ code: pc.currency?.code || pc.provider_currency_code,
67
+ name: pc.currency?.name || pc.provider_currency_code,
68
+ type: pc.currency?.currency_type || 'unknown',
69
+ symbol: pc.currency?.symbol || '',
70
+ network: pc.network?.code || null,
71
+ network_name: pc.network?.name || null,
72
+ min_amount: pc.min_amount,
73
+ max_amount: pc.max_amount,
74
+ fee_percentage: pc.fee_percentage,
75
+ fixed_fee: pc.fixed_fee,
76
+ provider_code: pc.provider_currency_code
77
+ }));
78
+
79
+ // If current currency is not supported by provider, reset it
80
+ if (this.form.currency_code && !this.currencies.find(c => c.code === this.form.currency_code)) {
81
+ this.form.currency_code = '';
82
+ this.conversionResult = null;
83
+ }
84
+ } catch (error) {
85
+ console.error('Failed to load provider currencies:', error);
86
+ this.currencies = [];
87
+ } finally {
88
+ this.loadingCurrencies = false;
89
+ }
90
+ },
91
+
92
+ async loadUsers() {
93
+ try {
94
+ const data = await PaymentAPI.admin.users.list();
95
+ this.users = data.results || data || [];
96
+
97
+ // If no users loaded, try to get current user info
98
+ if (this.users.length === 0) {
99
+ console.warn('No users loaded from admin API');
100
+ this.users = [{ id: '', username: 'Select User', email: '' }];
101
+ }
102
+ } catch (error) {
103
+ console.error('Failed to load users:', error);
104
+ // Set empty option for user selection
105
+ this.users = [{ id: '', username: 'Select User', email: '' }];
106
+ }
107
+ },
108
+
109
+ async onProviderChange() {
110
+ await this.loadProviderCurrencies();
111
+ },
112
+
113
+ async onAmountOrCurrencyChange() {
114
+ if (this.form.amount_usd && this.form.currency_code && this.form.currency_code !== 'USD') {
115
+ await this.convertCurrency();
116
+ } else {
117
+ this.conversionResult = null;
118
+ }
119
+ },
120
+
121
+ async convertCurrency() {
122
+ if (!this.form.amount_usd || !this.form.currency_code) return;
123
+
124
+ try {
125
+ const result = await PaymentAPI.currencies.convert('USD', this.form.currency_code, this.form.amount_usd);
126
+ this.conversionResult = {
127
+ amount: result.converted_amount,
128
+ rate: result.rate,
129
+ currency: this.form.currency_code
130
+ };
131
+ } catch (error) {
132
+ console.error('Currency conversion failed:', error);
133
+ this.conversionResult = null;
134
+ }
135
+ },
136
+
137
+ getCurrencyInfo(code) {
138
+ return this.currencies.find(c => c.code === code) ||
139
+ this.allCurrencies.find(c => c.code === code) ||
140
+ { code, name: code, type: 'unknown' };
141
+ },
142
+
143
+ validateForm() {
144
+ const errors = [];
145
+
146
+ if (!this.form.user) errors.push('User is required');
147
+ if (!this.form.amount_usd || this.form.amount_usd <= 0) errors.push('Valid amount is required');
148
+ if (!this.form.currency_code) errors.push('Currency is required');
149
+ if (!this.form.provider) errors.push('Provider is required');
150
+
151
+ return errors;
152
+ },
153
+
154
+ async submitForm() {
155
+ const errors = this.validateForm();
156
+ if (errors.length > 0) {
157
+ PaymentAPI.utils.showNotification(errors.join(', '), 'error');
158
+ return;
159
+ }
160
+
161
+ this.loading = true;
162
+
163
+ try {
164
+ const data = await PaymentAPI.admin.payments.create(this.form);
165
+ PaymentAPI.utils.showNotification('Payment created successfully!', 'success');
166
+ window.location.href = `/cfg/admin/django_cfg_payments/admin/payments/${data.id}/`;
167
+ } catch (error) {
168
+ console.error('Error:', error);
169
+ PaymentAPI.utils.showNotification(error.message || 'Failed to create payment', 'error');
170
+ } finally {
171
+ this.loading = false;
172
+ }
173
+ }
174
+ };
175
+ }