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
@@ -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
|
+
}
|