django-cfg 1.2.31__py3-none-any.whl → 1.3.1__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/api/health/views.py +4 -2
- django_cfg/apps/knowbase/config/settings.py +16 -15
- django_cfg/apps/payments/README.md +326 -0
- django_cfg/apps/payments/admin/__init__.py +20 -10
- django_cfg/apps/payments/admin/api_keys_admin.py +521 -237
- django_cfg/apps/payments/admin/balance_admin.py +592 -297
- django_cfg/apps/payments/admin/currencies_admin.py +526 -222
- django_cfg/apps/payments/admin/filters.py +306 -199
- django_cfg/apps/payments/admin/payments_admin.py +465 -70
- django_cfg/apps/payments/admin/subscriptions_admin.py +578 -128
- django_cfg/apps/payments/admin_interface/__init__.py +18 -0
- django_cfg/apps/payments/admin_interface/templates/payments/base.html +162 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +38 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/loading_spinner.html +16 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/notification.html +27 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_card.html +86 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +39 -0
- django_cfg/apps/payments/admin_interface/templates/payments/currency_converter.html +382 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +300 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +303 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +382 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_status.html +500 -0
- django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +594 -0
- django_cfg/apps/payments/admin_interface/views/__init__.py +23 -0
- django_cfg/apps/payments/admin_interface/views/payment_views.py +259 -0
- django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +37 -0
- django_cfg/apps/payments/apps.py +34 -9
- django_cfg/apps/payments/config/__init__.py +28 -51
- django_cfg/apps/payments/config/constance/__init__.py +22 -0
- django_cfg/apps/payments/config/constance/config_service.py +123 -0
- django_cfg/apps/payments/config/constance/fields.py +69 -0
- django_cfg/apps/payments/config/constance/settings.py +160 -0
- django_cfg/apps/payments/config/django_cfg_integration.py +202 -0
- django_cfg/apps/payments/config/helpers.py +130 -0
- django_cfg/apps/payments/management/__init__.py +1 -3
- django_cfg/apps/payments/management/commands/__init__.py +1 -3
- django_cfg/apps/payments/management/commands/manage_currencies.py +303 -151
- django_cfg/apps/payments/management/commands/manage_providers.py +333 -160
- django_cfg/apps/payments/middleware/__init__.py +3 -1
- django_cfg/apps/payments/middleware/api_access.py +329 -222
- django_cfg/apps/payments/middleware/rate_limiting.py +342 -152
- django_cfg/apps/payments/middleware/usage_tracking.py +249 -240
- django_cfg/apps/payments/migrations/0001_initial.py +708 -536
- django_cfg/apps/payments/models/__init__.py +13 -18
- django_cfg/apps/payments/models/api_keys.py +121 -43
- django_cfg/apps/payments/models/balance.py +150 -115
- django_cfg/apps/payments/models/base.py +68 -15
- django_cfg/apps/payments/models/currencies.py +172 -148
- django_cfg/apps/payments/models/managers/__init__.py +44 -0
- django_cfg/apps/payments/models/managers/api_key_managers.py +329 -0
- django_cfg/apps/payments/models/managers/balance_managers.py +599 -0
- django_cfg/apps/payments/models/managers/currency_managers.py +385 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +511 -0
- django_cfg/apps/payments/models/managers/subscription_managers.py +641 -0
- django_cfg/apps/payments/models/payments.py +235 -285
- django_cfg/apps/payments/models/subscriptions.py +257 -177
- django_cfg/apps/payments/models/tariffs.py +147 -40
- django_cfg/apps/payments/services/__init__.py +209 -56
- django_cfg/apps/payments/services/cache/__init__.py +6 -6
- django_cfg/apps/payments/services/cache/{simple_cache.py → cache_service.py} +112 -12
- django_cfg/apps/payments/services/core/__init__.py +10 -6
- django_cfg/apps/payments/services/core/balance_service.py +435 -360
- django_cfg/apps/payments/services/core/base.py +166 -0
- django_cfg/apps/payments/services/core/currency_service.py +478 -0
- django_cfg/apps/payments/services/core/payment_service.py +346 -467
- django_cfg/apps/payments/services/core/subscription_service.py +425 -481
- django_cfg/apps/payments/services/core/webhook_service.py +410 -0
- django_cfg/apps/payments/services/integrations/__init__.py +29 -0
- django_cfg/apps/payments/services/integrations/ngrok_service.py +47 -0
- django_cfg/apps/payments/services/integrations/providers_config.py +107 -0
- django_cfg/apps/payments/services/providers/__init__.py +9 -14
- django_cfg/apps/payments/services/providers/base.py +234 -174
- django_cfg/apps/payments/services/providers/nowpayments.py +478 -0
- django_cfg/apps/payments/services/providers/registry.py +367 -301
- django_cfg/apps/payments/services/types/__init__.py +78 -0
- django_cfg/apps/payments/services/types/data.py +177 -0
- django_cfg/apps/payments/services/types/requests.py +150 -0
- django_cfg/apps/payments/services/types/responses.py +156 -0
- django_cfg/apps/payments/services/types/webhooks.py +232 -0
- django_cfg/apps/payments/signals/__init__.py +33 -8
- django_cfg/apps/payments/signals/api_key_signals.py +210 -129
- django_cfg/apps/payments/signals/balance_signals.py +174 -0
- django_cfg/apps/payments/signals/payment_signals.py +128 -103
- django_cfg/apps/payments/signals/subscription_signals.py +194 -142
- django_cfg/apps/payments/static/payments/css/components.css +380 -0
- django_cfg/apps/payments/static/payments/css/dashboard.css +188 -0
- django_cfg/apps/payments/static/payments/js/components.js +545 -0
- django_cfg/apps/payments/static/payments/js/utils.js +412 -0
- django_cfg/apps/payments/templatetags/__init__.py +1 -1
- django_cfg/apps/payments/templatetags/payment_tags.py +466 -0
- django_cfg/apps/payments/urls.py +45 -48
- django_cfg/apps/payments/urls_admin.py +33 -42
- django_cfg/apps/payments/views/api/__init__.py +101 -0
- django_cfg/apps/payments/views/api/api_keys.py +387 -0
- django_cfg/apps/payments/views/api/balances.py +381 -0
- django_cfg/apps/payments/views/api/base.py +298 -0
- django_cfg/apps/payments/views/api/currencies.py +402 -0
- django_cfg/apps/payments/views/api/payments.py +415 -0
- django_cfg/apps/payments/views/api/subscriptions.py +475 -0
- django_cfg/apps/payments/views/api/webhooks.py +476 -0
- django_cfg/apps/payments/views/serializers/__init__.py +99 -0
- django_cfg/apps/payments/views/serializers/api_keys.py +424 -0
- django_cfg/apps/payments/views/serializers/balances.py +300 -0
- django_cfg/apps/payments/views/serializers/currencies.py +335 -0
- django_cfg/apps/payments/views/serializers/payments.py +387 -0
- django_cfg/apps/payments/views/serializers/subscriptions.py +429 -0
- django_cfg/apps/payments/views/serializers/webhooks.py +137 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +40 -4
- django_cfg/core/generation.py +25 -4
- django_cfg/core/integration/README.md +363 -0
- django_cfg/core/integration/__init__.py +47 -0
- django_cfg/core/integration/commands_collector.py +239 -0
- django_cfg/core/integration/display/__init__.py +15 -0
- django_cfg/core/integration/display/base.py +157 -0
- django_cfg/core/integration/display/ngrok.py +164 -0
- django_cfg/core/integration/display/startup.py +815 -0
- django_cfg/core/integration/url_integration.py +123 -0
- django_cfg/core/integration/version_checker.py +160 -0
- django_cfg/management/commands/auto_generate.py +4 -0
- django_cfg/management/commands/check_settings.py +6 -0
- django_cfg/management/commands/clear_constance.py +5 -2
- django_cfg/management/commands/create_token.py +6 -0
- django_cfg/management/commands/list_urls.py +6 -0
- django_cfg/management/commands/migrate_all.py +6 -0
- django_cfg/management/commands/migrator.py +3 -0
- django_cfg/management/commands/rundramatiq.py +6 -0
- django_cfg/management/commands/runserver_ngrok.py +51 -29
- django_cfg/management/commands/script.py +6 -0
- django_cfg/management/commands/show_config.py +12 -2
- django_cfg/management/commands/show_urls.py +4 -0
- django_cfg/management/commands/superuser.py +6 -0
- django_cfg/management/commands/task_clear.py +4 -1
- django_cfg/management/commands/task_status.py +3 -1
- django_cfg/management/commands/test_email.py +3 -0
- django_cfg/management/commands/test_telegram.py +6 -0
- django_cfg/management/commands/test_twilio.py +6 -0
- django_cfg/management/commands/tree.py +6 -0
- django_cfg/management/commands/validate_config.py +155 -149
- django_cfg/models/constance.py +31 -11
- django_cfg/models/payments.py +175 -492
- django_cfg/modules/django_logger.py +160 -146
- django_cfg/modules/django_unfold/dashboard.py +64 -16
- django_cfg/registry/core.py +1 -0
- django_cfg/template_archive/django_sample.zip +0 -0
- django_cfg/utils/smart_defaults.py +222 -571
- django_cfg/utils/toolkit.py +51 -11
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/METADATA +4 -1
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/RECORD +153 -185
- django_cfg/apps/payments/__init__.py +0 -8
- django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
- django_cfg/apps/payments/config/module.py +0 -70
- django_cfg/apps/payments/config/providers.py +0 -105
- django_cfg/apps/payments/config/settings.py +0 -96
- django_cfg/apps/payments/config/utils.py +0 -52
- django_cfg/apps/payments/decorators.py +0 -291
- django_cfg/apps/payments/management/commands/README.md +0 -146
- django_cfg/apps/payments/management/commands/currency_stats.py +0 -304
- django_cfg/apps/payments/managers/__init__.py +0 -23
- django_cfg/apps/payments/managers/api_key_manager.py +0 -35
- django_cfg/apps/payments/managers/balance_manager.py +0 -361
- django_cfg/apps/payments/managers/currency_manager.py +0 -306
- django_cfg/apps/payments/managers/payment_manager.py +0 -192
- django_cfg/apps/payments/managers/subscription_manager.py +0 -37
- django_cfg/apps/payments/managers/tariff_manager.py +0 -29
- django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +0 -241
- django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +0 -30
- django_cfg/apps/payments/models/events.py +0 -73
- django_cfg/apps/payments/serializers/__init__.py +0 -57
- django_cfg/apps/payments/serializers/api_keys.py +0 -51
- django_cfg/apps/payments/serializers/balance.py +0 -59
- django_cfg/apps/payments/serializers/currencies.py +0 -63
- django_cfg/apps/payments/serializers/payments.py +0 -62
- django_cfg/apps/payments/serializers/subscriptions.py +0 -71
- django_cfg/apps/payments/serializers/tariffs.py +0 -56
- django_cfg/apps/payments/services/billing/__init__.py +0 -8
- django_cfg/apps/payments/services/cache/base.py +0 -30
- django_cfg/apps/payments/services/core/fallback_service.py +0 -432
- django_cfg/apps/payments/services/internal_types.py +0 -461
- django_cfg/apps/payments/services/middleware/__init__.py +0 -8
- django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
- django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -76
- django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
- django_cfg/apps/payments/services/providers/cryptapi/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/cryptapi/config.py +0 -8
- django_cfg/apps/payments/services/providers/cryptapi/models.py +0 -192
- django_cfg/apps/payments/services/providers/cryptapi/provider.py +0 -439
- django_cfg/apps/payments/services/providers/cryptomus/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/cryptomus/models.py +0 -176
- django_cfg/apps/payments/services/providers/cryptomus/provider.py +0 -429
- django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +0 -564
- django_cfg/apps/payments/services/providers/models/__init__.py +0 -34
- django_cfg/apps/payments/services/providers/models/currencies.py +0 -190
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/nowpayments/models.py +0 -196
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +0 -380
- django_cfg/apps/payments/services/providers/stripe/__init__.py +0 -4
- django_cfg/apps/payments/services/providers/stripe/models.py +0 -184
- django_cfg/apps/payments/services/providers/stripe/provider.py +0 -109
- django_cfg/apps/payments/services/security/__init__.py +0 -34
- django_cfg/apps/payments/services/security/error_handler.py +0 -635
- django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
- django_cfg/apps/payments/services/security/webhook_validator.py +0 -474
- django_cfg/apps/payments/static/payments/css/payments.css +0 -340
- django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
- django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
- django_cfg/apps/payments/static/payments/js/theme.js +0 -86
- django_cfg/apps/payments/tasks/__init__.py +0 -12
- django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +0 -50
- django_cfg/apps/payments/templates/payments/base.html +0 -182
- django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
- django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
- django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -43
- django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
- django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -34
- django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -148
- django_cfg/apps/payments/templates/payments/dashboard.html +0 -258
- django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +0 -35
- django_cfg/apps/payments/templates/payments/payment_create.html +0 -579
- django_cfg/apps/payments/templates/payments/payment_detail.html +0 -373
- django_cfg/apps/payments/templates/payments/payment_list.html +0 -354
- django_cfg/apps/payments/templates/payments/stats.html +0 -261
- django_cfg/apps/payments/templates/payments/test.html +0 -213
- django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
- django_cfg/apps/payments/utils/__init__.py +0 -43
- django_cfg/apps/payments/utils/billing_utils.py +0 -342
- django_cfg/apps/payments/utils/config_utils.py +0 -239
- django_cfg/apps/payments/utils/middleware_utils.py +0 -228
- django_cfg/apps/payments/utils/validation_utils.py +0 -94
- django_cfg/apps/payments/views/__init__.py +0 -63
- django_cfg/apps/payments/views/api_key_views.py +0 -164
- django_cfg/apps/payments/views/balance_views.py +0 -75
- django_cfg/apps/payments/views/currency_views.py +0 -122
- django_cfg/apps/payments/views/payment_views.py +0 -149
- django_cfg/apps/payments/views/subscription_views.py +0 -135
- django_cfg/apps/payments/views/tariff_views.py +0 -131
- django_cfg/apps/payments/views/templates/__init__.py +0 -25
- django_cfg/apps/payments/views/templates/ajax.py +0 -451
- django_cfg/apps/payments/views/templates/base.py +0 -212
- django_cfg/apps/payments/views/templates/dashboard.py +0 -60
- django_cfg/apps/payments/views/templates/payment_detail.py +0 -102
- django_cfg/apps/payments/views/templates/payment_management.py +0 -158
- django_cfg/apps/payments/views/templates/qr_code.py +0 -174
- django_cfg/apps/payments/views/templates/stats.py +0 -244
- django_cfg/apps/payments/views/templates/utils.py +0 -181
- django_cfg/apps/payments/views/webhook_views.py +0 -266
- django_cfg/apps/payments/viewsets.py +0 -66
- django_cfg/core/integration.py +0 -160
- django_cfg/template_archive/.gitignore +0 -1
- django_cfg/template_archive/__init__.py +0 -0
- django_cfg/urls.py +0 -33
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,192 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Enhanced Payment manager for UniversalPayment model with query optimizations.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from django.db import models
|
6
|
-
from django.utils import timezone
|
7
|
-
from datetime import timedelta
|
8
|
-
from django_cfg.modules.django_logger import get_logger
|
9
|
-
|
10
|
-
logger = get_logger("payment_manager")
|
11
|
-
|
12
|
-
|
13
|
-
class PaymentQuerySet(models.QuerySet):
|
14
|
-
"""Custom QuerySet for UniversalPayment with optimizations."""
|
15
|
-
|
16
|
-
def with_user(self):
|
17
|
-
"""Select related user to prevent N+1 queries."""
|
18
|
-
return self.select_related('user')
|
19
|
-
|
20
|
-
def with_events(self):
|
21
|
-
"""Skip prefetch for events since they use CharField payment_id, not ForeignKey."""
|
22
|
-
# PaymentEvent uses CharField payment_id, not ForeignKey, so no reverse relation exists
|
23
|
-
# Events should be fetched separately when needed
|
24
|
-
return self
|
25
|
-
|
26
|
-
def optimized(self):
|
27
|
-
"""Get optimized queryset for admin and API views."""
|
28
|
-
return self.select_related('user').with_events()
|
29
|
-
|
30
|
-
def active(self):
|
31
|
-
"""Get active payments (not failed, cancelled, or refunded)."""
|
32
|
-
return self.exclude(
|
33
|
-
status__in=['failed', 'cancelled', 'refunded', 'expired']
|
34
|
-
)
|
35
|
-
|
36
|
-
def completed(self):
|
37
|
-
"""Get only completed payments."""
|
38
|
-
return self.filter(status='completed')
|
39
|
-
|
40
|
-
def pending(self):
|
41
|
-
"""Get pending payments."""
|
42
|
-
return self.filter(status='pending')
|
43
|
-
|
44
|
-
def by_provider(self, provider):
|
45
|
-
"""Filter by payment provider."""
|
46
|
-
return self.filter(provider=provider)
|
47
|
-
|
48
|
-
def recent(self, days=30):
|
49
|
-
"""Get payments from last N days."""
|
50
|
-
cutoff_date = timezone.now() - timedelta(days=days)
|
51
|
-
return self.filter(created_at__gte=cutoff_date)
|
52
|
-
|
53
|
-
def by_amount_range(self, min_amount=None, max_amount=None):
|
54
|
-
"""Filter by USD amount range."""
|
55
|
-
queryset = self
|
56
|
-
if min_amount is not None:
|
57
|
-
queryset = queryset.filter(amount_usd__gte=min_amount)
|
58
|
-
if max_amount is not None:
|
59
|
-
queryset = queryset.filter(amount_usd__lte=max_amount)
|
60
|
-
return queryset
|
61
|
-
|
62
|
-
def by_user(self, user):
|
63
|
-
"""Filter by user."""
|
64
|
-
return self.filter(user=user)
|
65
|
-
|
66
|
-
def expired(self):
|
67
|
-
"""Get expired payments."""
|
68
|
-
return self.filter(
|
69
|
-
expires_at__lt=timezone.now(),
|
70
|
-
status__in=['pending', 'confirming']
|
71
|
-
)
|
72
|
-
|
73
|
-
|
74
|
-
class UniversalPaymentManager(models.Manager):
|
75
|
-
"""Enhanced manager for UniversalPayment with optimization methods."""
|
76
|
-
|
77
|
-
def get_queryset(self):
|
78
|
-
"""Return custom QuerySet."""
|
79
|
-
return PaymentQuerySet(self.model, using=self._db)
|
80
|
-
|
81
|
-
def with_user(self):
|
82
|
-
"""Get payments with user data preloaded."""
|
83
|
-
return self.get_queryset().with_user()
|
84
|
-
|
85
|
-
def optimized(self):
|
86
|
-
"""Get optimized queryset for admin views."""
|
87
|
-
return self.get_queryset().optimized()
|
88
|
-
|
89
|
-
def active(self):
|
90
|
-
"""Get active payments."""
|
91
|
-
return self.get_queryset().active()
|
92
|
-
|
93
|
-
def completed(self):
|
94
|
-
"""Get completed payments."""
|
95
|
-
return self.get_queryset().completed()
|
96
|
-
|
97
|
-
def pending(self):
|
98
|
-
"""Get pending payments."""
|
99
|
-
return self.get_queryset().pending()
|
100
|
-
|
101
|
-
def recent(self, days=30):
|
102
|
-
"""Get recent payments."""
|
103
|
-
return self.get_queryset().recent(days)
|
104
|
-
|
105
|
-
def by_provider(self, provider):
|
106
|
-
"""Get payments by provider."""
|
107
|
-
return self.get_queryset().by_provider(provider)
|
108
|
-
|
109
|
-
def create_payment(self, user, amount_usd: float, currency_code: str, provider: str, **kwargs):
|
110
|
-
"""Create a payment with automatic field generation."""
|
111
|
-
from uuid import uuid4
|
112
|
-
|
113
|
-
# Generate unique internal payment ID if not provided
|
114
|
-
internal_payment_id = kwargs.pop('internal_payment_id', f"PAY_{uuid4().hex[:8].upper()}")
|
115
|
-
|
116
|
-
payment = self.create(
|
117
|
-
user=user,
|
118
|
-
internal_payment_id=internal_payment_id,
|
119
|
-
amount_usd=amount_usd,
|
120
|
-
currency_code=currency_code.upper(),
|
121
|
-
provider=provider,
|
122
|
-
status=self.model.PaymentStatus.PENDING,
|
123
|
-
**kwargs
|
124
|
-
)
|
125
|
-
|
126
|
-
return payment
|
127
|
-
|
128
|
-
def get_pending_payments(self, user=None):
|
129
|
-
"""Get pending payments for user or all users."""
|
130
|
-
queryset = self.pending()
|
131
|
-
if user:
|
132
|
-
queryset = queryset.by_user(user)
|
133
|
-
return queryset.with_user()
|
134
|
-
|
135
|
-
def get_completed_payments(self, user=None):
|
136
|
-
"""Get completed payments for user or all users."""
|
137
|
-
queryset = self.completed()
|
138
|
-
if user:
|
139
|
-
queryset = queryset.by_user(user)
|
140
|
-
return queryset.with_user()
|
141
|
-
|
142
|
-
def get_failed_payments(self, user=None):
|
143
|
-
"""Get failed/expired payments for user or all users."""
|
144
|
-
queryset = self.filter(status__in=[
|
145
|
-
self.model.PaymentStatus.FAILED,
|
146
|
-
self.model.PaymentStatus.EXPIRED
|
147
|
-
])
|
148
|
-
if user:
|
149
|
-
queryset = queryset.by_user(user)
|
150
|
-
return queryset.with_user()
|
151
|
-
|
152
|
-
def get_user_stats(self, user):
|
153
|
-
"""Get payment statistics for a user."""
|
154
|
-
user_payments = self.by_user(user)
|
155
|
-
|
156
|
-
return {
|
157
|
-
'total_payments': user_payments.count(),
|
158
|
-
'completed_payments': user_payments.completed().count(),
|
159
|
-
'pending_payments': user_payments.pending().count(),
|
160
|
-
'failed_payments': user_payments.filter(status='failed').count(),
|
161
|
-
'total_amount_usd': user_payments.completed().aggregate(
|
162
|
-
total=models.Sum('amount_usd')
|
163
|
-
)['total'] or 0,
|
164
|
-
'recent_payments_30d': user_payments.recent(30).count(),
|
165
|
-
}
|
166
|
-
|
167
|
-
def get_provider_stats(self, provider=None):
|
168
|
-
"""Get payment statistics by provider."""
|
169
|
-
if provider:
|
170
|
-
payments = self.by_provider(provider)
|
171
|
-
else:
|
172
|
-
payments = self.all()
|
173
|
-
|
174
|
-
return {
|
175
|
-
'total_payments': payments.count(),
|
176
|
-
'completed_payments': payments.completed().count(),
|
177
|
-
'pending_payments': payments.pending().count(),
|
178
|
-
'success_rate': (
|
179
|
-
payments.completed().count() / max(payments.count(), 1) * 100
|
180
|
-
),
|
181
|
-
'total_volume_usd': payments.completed().aggregate(
|
182
|
-
total=models.Sum('amount_usd')
|
183
|
-
)['total'] or 0,
|
184
|
-
}
|
185
|
-
|
186
|
-
def mark_expired_payments(self):
|
187
|
-
"""Mark expired payments as expired."""
|
188
|
-
expired_count = self.expired().update(
|
189
|
-
status=self.model.PaymentStatus.EXPIRED,
|
190
|
-
updated_at=timezone.now()
|
191
|
-
)
|
192
|
-
return expired_count
|
@@ -1,37 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Subscription managers.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from django.db import models
|
6
|
-
from django.utils import timezone
|
7
|
-
|
8
|
-
|
9
|
-
class SubscriptionManager(models.Manager):
|
10
|
-
"""Manager for Subscription model."""
|
11
|
-
|
12
|
-
def get_active_subscriptions(self, user=None):
|
13
|
-
"""Get active subscriptions."""
|
14
|
-
queryset = self.filter(
|
15
|
-
status='active',
|
16
|
-
expires_at__gt=timezone.now()
|
17
|
-
)
|
18
|
-
if user:
|
19
|
-
queryset = queryset.filter(user=user)
|
20
|
-
return queryset
|
21
|
-
|
22
|
-
def get_expired_subscriptions(self, user=None):
|
23
|
-
"""Get expired subscriptions."""
|
24
|
-
queryset = self.filter(
|
25
|
-
expires_at__lte=timezone.now()
|
26
|
-
)
|
27
|
-
if user:
|
28
|
-
queryset = queryset.filter(user=user)
|
29
|
-
return queryset
|
30
|
-
|
31
|
-
|
32
|
-
class EndpointGroupManager(models.Manager):
|
33
|
-
"""Manager for EndpointGroup model."""
|
34
|
-
|
35
|
-
def get_active_groups(self):
|
36
|
-
"""Get active endpoint groups."""
|
37
|
-
return self.filter(is_active=True)
|
@@ -1,29 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Tariff managers.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from django.db import models
|
6
|
-
|
7
|
-
|
8
|
-
class TariffManager(models.Manager):
|
9
|
-
"""Manager for Tariff model."""
|
10
|
-
|
11
|
-
def get_active_tariffs(self):
|
12
|
-
"""Get active tariffs."""
|
13
|
-
return self.filter(is_active=True).order_by('monthly_price')
|
14
|
-
|
15
|
-
def get_free_tariffs(self):
|
16
|
-
"""Get free tariffs."""
|
17
|
-
return self.filter(monthly_price=0, is_active=True)
|
18
|
-
|
19
|
-
def get_paid_tariffs(self):
|
20
|
-
"""Get paid tariffs."""
|
21
|
-
return self.filter(monthly_price__gt=0, is_active=True)
|
22
|
-
|
23
|
-
|
24
|
-
class TariffEndpointGroupManager(models.Manager):
|
25
|
-
"""Manager for TariffEndpointGroup model."""
|
26
|
-
|
27
|
-
def get_enabled_for_tariff(self, tariff):
|
28
|
-
"""Get enabled endpoint groups for tariff."""
|
29
|
-
return self.filter(tariff=tariff, is_enabled=True)
|
@@ -1,241 +0,0 @@
|
|
1
|
-
# Generated by Django 5.2.6 on 2025-09-24 19:54
|
2
|
-
|
3
|
-
import django.db.models.deletion
|
4
|
-
from django.db import migrations, models
|
5
|
-
|
6
|
-
|
7
|
-
class Migration(migrations.Migration):
|
8
|
-
dependencies = [
|
9
|
-
("django_cfg_payments", "0001_initial"),
|
10
|
-
]
|
11
|
-
|
12
|
-
operations = [
|
13
|
-
migrations.CreateModel(
|
14
|
-
name="Network",
|
15
|
-
fields=[
|
16
|
-
(
|
17
|
-
"id",
|
18
|
-
models.BigAutoField(
|
19
|
-
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
20
|
-
),
|
21
|
-
),
|
22
|
-
("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
|
23
|
-
("updated_at", models.DateTimeField(auto_now=True)),
|
24
|
-
(
|
25
|
-
"code",
|
26
|
-
models.CharField(
|
27
|
-
help_text="Network code: ethereum, bitcoin, tron, bsc",
|
28
|
-
max_length=20,
|
29
|
-
unique=True,
|
30
|
-
),
|
31
|
-
),
|
32
|
-
(
|
33
|
-
"name",
|
34
|
-
models.CharField(
|
35
|
-
help_text="Network name: Ethereum, Bitcoin, TRON, BSC", max_length=100
|
36
|
-
),
|
37
|
-
),
|
38
|
-
],
|
39
|
-
options={
|
40
|
-
"verbose_name": "Network",
|
41
|
-
"verbose_name_plural": "Networks",
|
42
|
-
"db_table": "payment_networks",
|
43
|
-
"ordering": ["name"],
|
44
|
-
},
|
45
|
-
),
|
46
|
-
migrations.CreateModel(
|
47
|
-
name="ProviderCurrency",
|
48
|
-
fields=[
|
49
|
-
(
|
50
|
-
"id",
|
51
|
-
models.BigAutoField(
|
52
|
-
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
53
|
-
),
|
54
|
-
),
|
55
|
-
("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
|
56
|
-
("updated_at", models.DateTimeField(auto_now=True)),
|
57
|
-
(
|
58
|
-
"provider_name",
|
59
|
-
models.CharField(
|
60
|
-
help_text="Provider: nowpayments, stripe, cryptomus", max_length=50
|
61
|
-
),
|
62
|
-
),
|
63
|
-
(
|
64
|
-
"provider_currency_code",
|
65
|
-
models.CharField(
|
66
|
-
help_text="Provider code: USDTERC20, USDTBSC, usd", max_length=20
|
67
|
-
),
|
68
|
-
),
|
69
|
-
(
|
70
|
-
"min_amount",
|
71
|
-
models.DecimalField(
|
72
|
-
blank=True,
|
73
|
-
decimal_places=8,
|
74
|
-
help_text="Minimum payment amount",
|
75
|
-
max_digits=20,
|
76
|
-
null=True,
|
77
|
-
),
|
78
|
-
),
|
79
|
-
(
|
80
|
-
"max_amount",
|
81
|
-
models.DecimalField(
|
82
|
-
blank=True,
|
83
|
-
decimal_places=8,
|
84
|
-
help_text="Maximum payment amount (null = no limit)",
|
85
|
-
max_digits=20,
|
86
|
-
null=True,
|
87
|
-
),
|
88
|
-
),
|
89
|
-
("is_enabled", models.BooleanField(default=True, help_text="Enabled by provider")),
|
90
|
-
(
|
91
|
-
"available_for_payment",
|
92
|
-
models.BooleanField(default=True, help_text="Can receive payments"),
|
93
|
-
),
|
94
|
-
(
|
95
|
-
"available_for_payout",
|
96
|
-
models.BooleanField(default=True, help_text="Can send payouts"),
|
97
|
-
),
|
98
|
-
(
|
99
|
-
"is_popular",
|
100
|
-
models.BooleanField(default=False, help_text="Popular/recommended by provider"),
|
101
|
-
),
|
102
|
-
(
|
103
|
-
"is_stable",
|
104
|
-
models.BooleanField(default=False, help_text="Stable coin (USDT, USDC, etc.)"),
|
105
|
-
),
|
106
|
-
(
|
107
|
-
"priority",
|
108
|
-
models.IntegerField(
|
109
|
-
default=0, help_text="Display priority (higher = shown first)"
|
110
|
-
),
|
111
|
-
),
|
112
|
-
(
|
113
|
-
"logo_url",
|
114
|
-
models.URLField(blank=True, help_text="Currency logo/icon URL from provider"),
|
115
|
-
),
|
116
|
-
(
|
117
|
-
"metadata",
|
118
|
-
models.JSONField(
|
119
|
-
blank=True,
|
120
|
-
default=dict,
|
121
|
-
help_text="All provider-specific data: logo_url, smart_contract, wallet_regex, commission_percent, etc.",
|
122
|
-
),
|
123
|
-
),
|
124
|
-
],
|
125
|
-
options={
|
126
|
-
"verbose_name": "Provider Currency",
|
127
|
-
"verbose_name_plural": "Provider Currencies",
|
128
|
-
"db_table": "payment_provider_currencies",
|
129
|
-
"ordering": ["-priority", "provider_name", "base_currency__code"],
|
130
|
-
},
|
131
|
-
),
|
132
|
-
migrations.AlterUniqueTogether(
|
133
|
-
name="currencynetwork",
|
134
|
-
unique_together=None,
|
135
|
-
),
|
136
|
-
migrations.RemoveField(
|
137
|
-
model_name="currencynetwork",
|
138
|
-
name="currency",
|
139
|
-
),
|
140
|
-
migrations.AlterModelOptions(
|
141
|
-
name="currency",
|
142
|
-
options={
|
143
|
-
"ordering": ["currency_type", "code"],
|
144
|
-
"verbose_name": "Currency",
|
145
|
-
"verbose_name_plural": "Currencies",
|
146
|
-
},
|
147
|
-
),
|
148
|
-
migrations.RemoveIndex(
|
149
|
-
model_name="currency",
|
150
|
-
name="payment_cur_code_e2a506_idx",
|
151
|
-
),
|
152
|
-
migrations.RemoveIndex(
|
153
|
-
model_name="currency",
|
154
|
-
name="payment_cur_currenc_6057a9_idx",
|
155
|
-
),
|
156
|
-
migrations.RemoveIndex(
|
157
|
-
model_name="currency",
|
158
|
-
name="payment_cur_is_acti_8d558f_idx",
|
159
|
-
),
|
160
|
-
migrations.RemoveField(
|
161
|
-
model_name="currency",
|
162
|
-
name="decimal_places",
|
163
|
-
),
|
164
|
-
migrations.RemoveField(
|
165
|
-
model_name="currency",
|
166
|
-
name="is_active",
|
167
|
-
),
|
168
|
-
migrations.RemoveField(
|
169
|
-
model_name="currency",
|
170
|
-
name="min_payment_amount",
|
171
|
-
),
|
172
|
-
migrations.RemoveField(
|
173
|
-
model_name="currency",
|
174
|
-
name="rate_updated_at",
|
175
|
-
),
|
176
|
-
migrations.RemoveField(
|
177
|
-
model_name="currency",
|
178
|
-
name="symbol",
|
179
|
-
),
|
180
|
-
migrations.RemoveField(
|
181
|
-
model_name="currency",
|
182
|
-
name="usd_rate",
|
183
|
-
),
|
184
|
-
migrations.AlterField(
|
185
|
-
model_name="currency",
|
186
|
-
name="code",
|
187
|
-
field=models.CharField(
|
188
|
-
help_text="Clean currency code: BTC, USDT, ETH, USD (NO network suffixes)",
|
189
|
-
max_length=10,
|
190
|
-
unique=True,
|
191
|
-
),
|
192
|
-
),
|
193
|
-
migrations.AlterField(
|
194
|
-
model_name="currency",
|
195
|
-
name="currency_type",
|
196
|
-
field=models.CharField(
|
197
|
-
choices=[("fiat", "Fiat Currency"), ("crypto", "Cryptocurrency")],
|
198
|
-
help_text="fiat or crypto",
|
199
|
-
max_length=10,
|
200
|
-
),
|
201
|
-
),
|
202
|
-
migrations.AlterField(
|
203
|
-
model_name="currency",
|
204
|
-
name="name",
|
205
|
-
field=models.CharField(
|
206
|
-
help_text="Currency name: Bitcoin, Tether USD, Ethereum", max_length=100
|
207
|
-
),
|
208
|
-
),
|
209
|
-
migrations.AddField(
|
210
|
-
model_name="providercurrency",
|
211
|
-
name="base_currency",
|
212
|
-
field=models.ForeignKey(
|
213
|
-
help_text="Base currency: BTC, USDT, ETH",
|
214
|
-
on_delete=django.db.models.deletion.CASCADE,
|
215
|
-
related_name="provider_mappings",
|
216
|
-
to="django_cfg_payments.currency",
|
217
|
-
),
|
218
|
-
),
|
219
|
-
migrations.AddField(
|
220
|
-
model_name="providercurrency",
|
221
|
-
name="network",
|
222
|
-
field=models.ForeignKey(
|
223
|
-
blank=True,
|
224
|
-
help_text="Network for crypto (null for fiat)",
|
225
|
-
null=True,
|
226
|
-
on_delete=django.db.models.deletion.CASCADE,
|
227
|
-
related_name="provider_currencies",
|
228
|
-
to="django_cfg_payments.network",
|
229
|
-
),
|
230
|
-
),
|
231
|
-
migrations.DeleteModel(
|
232
|
-
name="CurrencyNetwork",
|
233
|
-
),
|
234
|
-
migrations.AlterUniqueTogether(
|
235
|
-
name="providercurrency",
|
236
|
-
unique_together={
|
237
|
-
("provider_name", "base_currency", "network"),
|
238
|
-
("provider_name", "provider_currency_code"),
|
239
|
-
},
|
240
|
-
),
|
241
|
-
]
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# Generated by Django 5.2.6 on 2025-09-25 06:06
|
2
|
-
|
3
|
-
from django.db import migrations, models
|
4
|
-
|
5
|
-
|
6
|
-
class Migration(migrations.Migration):
|
7
|
-
dependencies = [
|
8
|
-
("django_cfg_payments", "0002_network_providercurrency_and_more"),
|
9
|
-
]
|
10
|
-
|
11
|
-
operations = [
|
12
|
-
migrations.AddField(
|
13
|
-
model_name="currency",
|
14
|
-
name="rate_updated_at",
|
15
|
-
field=models.DateTimeField(
|
16
|
-
blank=True, help_text="When the USD rate was last updated", null=True
|
17
|
-
),
|
18
|
-
),
|
19
|
-
migrations.AddField(
|
20
|
-
model_name="currency",
|
21
|
-
name="usd_rate",
|
22
|
-
field=models.DecimalField(
|
23
|
-
blank=True,
|
24
|
-
decimal_places=8,
|
25
|
-
help_text="Cached USD exchange rate (1 CURRENCY = X USD)",
|
26
|
-
max_digits=20,
|
27
|
-
null=True,
|
28
|
-
),
|
29
|
-
),
|
30
|
-
]
|
@@ -1,73 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Event sourcing models for the universal payments system.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from django.db import models
|
6
|
-
from .base import UUIDTimestampedModel
|
7
|
-
|
8
|
-
|
9
|
-
class PaymentEvent(UUIDTimestampedModel):
|
10
|
-
"""Event sourcing for payment operations - immutable audit trail."""
|
11
|
-
|
12
|
-
class EventType(models.TextChoices):
|
13
|
-
PAYMENT_CREATED = 'payment_created', 'Payment Created'
|
14
|
-
WEBHOOK_RECEIVED = 'webhook_received', 'Webhook Received'
|
15
|
-
WEBHOOK_PROCESSED = 'webhook_processed', 'Webhook Processed'
|
16
|
-
BALANCE_UPDATED = 'balance_updated', 'Balance Updated'
|
17
|
-
REFUND_PROCESSED = 'refund_processed', 'Refund Processed'
|
18
|
-
STATUS_CHANGED = 'status_changed', 'Status Changed'
|
19
|
-
ERROR_OCCURRED = 'error_occurred', 'Error Occurred'
|
20
|
-
|
21
|
-
# Event identification
|
22
|
-
payment_id = models.CharField(
|
23
|
-
max_length=255,
|
24
|
-
db_index=True,
|
25
|
-
help_text="Payment identifier"
|
26
|
-
)
|
27
|
-
event_type = models.CharField(
|
28
|
-
max_length=50,
|
29
|
-
choices=EventType.choices,
|
30
|
-
db_index=True,
|
31
|
-
help_text="Type of event"
|
32
|
-
)
|
33
|
-
sequence_number = models.PositiveBigIntegerField(
|
34
|
-
help_text="Sequential number per payment"
|
35
|
-
)
|
36
|
-
|
37
|
-
# Event data (JSON for flexibility)
|
38
|
-
event_data = models.JSONField(
|
39
|
-
help_text="Event data payload"
|
40
|
-
)
|
41
|
-
|
42
|
-
# Operational metadata
|
43
|
-
processed_by = models.CharField(
|
44
|
-
max_length=100,
|
45
|
-
help_text="Worker/server that processed this event"
|
46
|
-
)
|
47
|
-
correlation_id = models.CharField(
|
48
|
-
max_length=255,
|
49
|
-
null=True,
|
50
|
-
blank=True,
|
51
|
-
help_text="Correlation ID for tracing"
|
52
|
-
)
|
53
|
-
idempotency_key = models.CharField(
|
54
|
-
max_length=255,
|
55
|
-
unique=True,
|
56
|
-
help_text="Idempotency key to prevent duplicates"
|
57
|
-
)
|
58
|
-
|
59
|
-
class Meta:
|
60
|
-
db_table = 'payment_events'
|
61
|
-
verbose_name = "Payment Event"
|
62
|
-
verbose_name_plural = "Payment Events"
|
63
|
-
indexes = [
|
64
|
-
models.Index(fields=['payment_id', 'sequence_number']),
|
65
|
-
models.Index(fields=['event_type', 'created_at']),
|
66
|
-
models.Index(fields=['idempotency_key']),
|
67
|
-
models.Index(fields=['correlation_id']),
|
68
|
-
models.Index(fields=['created_at']),
|
69
|
-
]
|
70
|
-
ordering = ['sequence_number']
|
71
|
-
|
72
|
-
def __str__(self):
|
73
|
-
return f"Event {self.sequence_number}: {self.event_type} for {self.payment_id}"
|
@@ -1,57 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
DRF serializers for the universal payments system.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from .balance import (
|
6
|
-
UserBalanceSerializer, TransactionSerializer, TransactionListSerializer
|
7
|
-
)
|
8
|
-
from .payments import (
|
9
|
-
UniversalPaymentSerializer, PaymentCreateSerializer, PaymentListSerializer
|
10
|
-
)
|
11
|
-
from .subscriptions import (
|
12
|
-
SubscriptionSerializer, SubscriptionCreateSerializer, SubscriptionListSerializer,
|
13
|
-
EndpointGroupSerializer
|
14
|
-
)
|
15
|
-
from .api_keys import (
|
16
|
-
APIKeySerializer, APIKeyCreateSerializer, APIKeyListSerializer
|
17
|
-
)
|
18
|
-
from .currencies import (
|
19
|
-
CurrencySerializer, NetworkSerializer, ProviderCurrencySerializer, CurrencyListSerializer
|
20
|
-
)
|
21
|
-
from .tariffs import (
|
22
|
-
TariffSerializer, TariffEndpointGroupSerializer, TariffListSerializer
|
23
|
-
)
|
24
|
-
|
25
|
-
__all__ = [
|
26
|
-
# Balance
|
27
|
-
'UserBalanceSerializer',
|
28
|
-
'TransactionSerializer',
|
29
|
-
'TransactionListSerializer',
|
30
|
-
|
31
|
-
# Payments
|
32
|
-
'UniversalPaymentSerializer',
|
33
|
-
'PaymentCreateSerializer',
|
34
|
-
'PaymentListSerializer',
|
35
|
-
|
36
|
-
# Subscriptions
|
37
|
-
'SubscriptionSerializer',
|
38
|
-
'SubscriptionCreateSerializer',
|
39
|
-
'SubscriptionListSerializer',
|
40
|
-
'EndpointGroupSerializer',
|
41
|
-
|
42
|
-
# API Keys
|
43
|
-
'APIKeySerializer',
|
44
|
-
'APIKeyCreateSerializer',
|
45
|
-
'APIKeyListSerializer',
|
46
|
-
|
47
|
-
# Currencies
|
48
|
-
'CurrencySerializer',
|
49
|
-
'NetworkSerializer',
|
50
|
-
'ProviderCurrencySerializer',
|
51
|
-
'CurrencyListSerializer',
|
52
|
-
|
53
|
-
# Tariffs
|
54
|
-
'TariffSerializer',
|
55
|
-
'TariffEndpointGroupSerializer',
|
56
|
-
'TariffListSerializer',
|
57
|
-
]
|