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,30 +1,83 @@
|
|
1
1
|
"""
|
2
|
-
Base
|
2
|
+
Base models for the Universal Payment System v2.0.
|
3
|
+
|
4
|
+
Provides common functionality for all payment-related models.
|
3
5
|
"""
|
4
6
|
|
5
7
|
import uuid
|
6
8
|
from django.db import models
|
7
|
-
|
8
|
-
|
9
|
-
class TimestampedModel(models.Model):
|
10
|
-
"""Base model with automatic timestamps."""
|
11
|
-
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
|
12
|
-
updated_at = models.DateTimeField(auto_now=True)
|
13
|
-
|
14
|
-
class Meta:
|
15
|
-
abstract = True
|
9
|
+
from django.utils import timezone
|
16
10
|
|
17
11
|
|
18
12
|
class UUIDTimestampedModel(models.Model):
|
19
|
-
"""
|
13
|
+
"""
|
14
|
+
Abstract base model with UUID primary key and timestamps.
|
15
|
+
|
16
|
+
Provides:
|
17
|
+
- UUID primary key for security and scalability
|
18
|
+
- Created/updated timestamps with timezone awareness
|
19
|
+
- Common functionality for all payment models
|
20
|
+
"""
|
21
|
+
|
20
22
|
id = models.UUIDField(
|
21
23
|
primary_key=True,
|
22
24
|
default=uuid.uuid4,
|
23
25
|
editable=False,
|
24
|
-
help_text="Unique identifier"
|
26
|
+
help_text="Unique identifier for this record"
|
27
|
+
)
|
28
|
+
|
29
|
+
created_at = models.DateTimeField(
|
30
|
+
auto_now_add=True,
|
31
|
+
db_index=True,
|
32
|
+
help_text="When this record was created"
|
33
|
+
)
|
34
|
+
|
35
|
+
updated_at = models.DateTimeField(
|
36
|
+
auto_now=True,
|
37
|
+
help_text="When this record was last updated"
|
25
38
|
)
|
26
|
-
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
|
27
|
-
updated_at = models.DateTimeField(auto_now=True)
|
28
39
|
|
29
40
|
class Meta:
|
30
|
-
abstract = True
|
41
|
+
abstract = True
|
42
|
+
ordering = ['-created_at']
|
43
|
+
|
44
|
+
def __str__(self):
|
45
|
+
"""String representation showing ID and creation time."""
|
46
|
+
return f"{self.__class__.__name__}({str(self.id)[:8]}...)"
|
47
|
+
|
48
|
+
def __repr__(self):
|
49
|
+
"""Developer-friendly representation."""
|
50
|
+
return f"<{self.__class__.__name__}: {str(self.id)}>"
|
51
|
+
|
52
|
+
@property
|
53
|
+
def age_in_seconds(self) -> int:
|
54
|
+
"""Get age of this record in seconds."""
|
55
|
+
return int((timezone.now() - self.created_at).total_seconds())
|
56
|
+
|
57
|
+
@property
|
58
|
+
def is_recent(self) -> bool:
|
59
|
+
"""Check if record was created in the last hour."""
|
60
|
+
return self.age_in_seconds < 3600
|
61
|
+
|
62
|
+
|
63
|
+
class TimestampedModel(models.Model):
|
64
|
+
"""
|
65
|
+
Abstract base model with auto-incrementing ID and timestamps.
|
66
|
+
|
67
|
+
Use this for models that don't need UUID (like configuration models).
|
68
|
+
"""
|
69
|
+
|
70
|
+
created_at = models.DateTimeField(
|
71
|
+
auto_now_add=True,
|
72
|
+
db_index=True,
|
73
|
+
help_text="When this record was created"
|
74
|
+
)
|
75
|
+
|
76
|
+
updated_at = models.DateTimeField(
|
77
|
+
auto_now=True,
|
78
|
+
help_text="When this record was last updated"
|
79
|
+
)
|
80
|
+
|
81
|
+
class Meta:
|
82
|
+
abstract = True
|
83
|
+
ordering = ['-created_at']
|
@@ -1,254 +1,278 @@
|
|
1
1
|
"""
|
2
|
-
Currency models for the
|
2
|
+
Currency models for the Universal Payment System v2.0.
|
3
|
+
|
4
|
+
Handles multi-provider currency support with integration to django_currency module.
|
3
5
|
"""
|
4
6
|
|
5
7
|
from django.db import models
|
8
|
+
from django.core.validators import MinLengthValidator, MaxLengthValidator
|
9
|
+
from django.core.exceptions import ValidationError
|
6
10
|
from .base import TimestampedModel
|
7
11
|
|
8
|
-
# Currency converter import moved inside methods to avoid circular imports
|
9
12
|
|
10
13
|
class Currency(TimestampedModel):
|
11
|
-
"""
|
14
|
+
"""
|
15
|
+
Universal currency model supporting both fiat and crypto.
|
16
|
+
|
17
|
+
Integrates with django_currency module for rate conversion.
|
18
|
+
"""
|
12
19
|
|
13
20
|
class CurrencyType(models.TextChoices):
|
14
21
|
FIAT = "fiat", "Fiat Currency"
|
15
22
|
CRYPTO = "crypto", "Cryptocurrency"
|
16
23
|
|
17
|
-
# Core fields - only essentials
|
18
24
|
code = models.CharField(
|
19
25
|
max_length=10,
|
20
26
|
unique=True,
|
21
|
-
|
27
|
+
validators=[MinLengthValidator(3), MaxLengthValidator(10)],
|
28
|
+
help_text="Currency code (e.g., BTC, USD, ETH)"
|
22
29
|
)
|
30
|
+
|
23
31
|
name = models.CharField(
|
24
32
|
max_length=100,
|
25
|
-
help_text="
|
33
|
+
help_text="Full currency name (e.g., Bitcoin, US Dollar)"
|
26
34
|
)
|
35
|
+
|
27
36
|
currency_type = models.CharField(
|
28
37
|
max_length=10,
|
29
38
|
choices=CurrencyType.choices,
|
30
|
-
help_text="
|
39
|
+
help_text="Type of currency"
|
31
40
|
)
|
32
41
|
|
33
|
-
|
34
|
-
|
35
|
-
max_digits=20,
|
36
|
-
decimal_places=8,
|
37
|
-
null=True,
|
42
|
+
symbol = models.CharField(
|
43
|
+
max_length=10,
|
38
44
|
blank=True,
|
39
|
-
help_text="
|
45
|
+
help_text="Currency symbol (e.g., $, ₿, Ξ)"
|
40
46
|
)
|
41
47
|
|
42
|
-
|
43
|
-
|
48
|
+
decimal_places = models.PositiveSmallIntegerField(
|
49
|
+
default=8,
|
50
|
+
help_text="Number of decimal places for this currency"
|
51
|
+
)
|
52
|
+
|
53
|
+
is_active = models.BooleanField(
|
54
|
+
default=True,
|
55
|
+
help_text="Whether this currency is available for payments"
|
56
|
+
)
|
57
|
+
|
58
|
+
# Integration with django_currency
|
59
|
+
exchange_rate_source = models.CharField(
|
60
|
+
max_length=50,
|
44
61
|
blank=True,
|
45
|
-
help_text="
|
62
|
+
help_text="Source for exchange rates (auto-detected by django_currency)"
|
46
63
|
)
|
47
64
|
|
48
|
-
#
|
49
|
-
from
|
65
|
+
# Manager
|
66
|
+
from .managers.currency_managers import CurrencyManager
|
50
67
|
objects = CurrencyManager()
|
51
68
|
|
52
69
|
class Meta:
|
53
|
-
db_table = '
|
54
|
-
verbose_name =
|
55
|
-
verbose_name_plural =
|
70
|
+
db_table = 'payments_currencies'
|
71
|
+
verbose_name = 'Currency'
|
72
|
+
verbose_name_plural = 'Currencies'
|
56
73
|
ordering = ['currency_type', 'code']
|
74
|
+
indexes = [
|
75
|
+
models.Index(fields=['currency_type', 'is_active']),
|
76
|
+
models.Index(fields=['code']),
|
77
|
+
]
|
57
78
|
|
58
79
|
def __str__(self):
|
59
|
-
return f"{self.code}
|
80
|
+
return f"{self.code} ({self.name})"
|
60
81
|
|
61
|
-
|
62
|
-
|
63
|
-
|
82
|
+
def clean(self):
|
83
|
+
"""Validate currency data."""
|
84
|
+
if self.code:
|
85
|
+
self.code = self.code.upper()
|
86
|
+
|
87
|
+
# Validate decimal places based on currency type
|
88
|
+
if self.currency_type == self.CurrencyType.FIAT and self.decimal_places > 4:
|
89
|
+
raise ValidationError("Fiat currencies should not have more than 4 decimal places")
|
90
|
+
|
91
|
+
if self.currency_type == self.CurrencyType.CRYPTO and self.decimal_places > 18:
|
92
|
+
raise ValidationError("Crypto currencies should not have more than 18 decimal places")
|
64
93
|
|
65
94
|
@property
|
66
95
|
def is_crypto(self) -> bool:
|
96
|
+
"""Check if this is a cryptocurrency."""
|
67
97
|
return self.currency_type == self.CurrencyType.CRYPTO
|
98
|
+
|
99
|
+
@property
|
100
|
+
def is_fiat(self) -> bool:
|
101
|
+
"""Check if this is a fiat currency."""
|
102
|
+
return self.currency_type == self.CurrencyType.FIAT
|
68
103
|
|
69
104
|
|
70
105
|
class Network(TimestampedModel):
|
71
|
-
"""
|
106
|
+
"""
|
107
|
+
Blockchain network model for cryptocurrency payments.
|
108
|
+
|
109
|
+
Represents different networks like Ethereum, Bitcoin, Polygon, etc.
|
110
|
+
"""
|
111
|
+
|
112
|
+
name = models.CharField(
|
113
|
+
max_length=50,
|
114
|
+
unique=True,
|
115
|
+
help_text="Network name (e.g., Ethereum, Bitcoin, Polygon)"
|
116
|
+
)
|
72
117
|
|
73
118
|
code = models.CharField(
|
74
119
|
max_length=20,
|
75
120
|
unique=True,
|
76
|
-
help_text="Network code
|
121
|
+
help_text="Network code (e.g., ETH, BTC, MATIC)"
|
77
122
|
)
|
78
|
-
|
79
|
-
|
80
|
-
|
123
|
+
|
124
|
+
native_currency = models.ForeignKey(
|
125
|
+
Currency,
|
126
|
+
on_delete=models.PROTECT,
|
127
|
+
related_name='native_networks',
|
128
|
+
help_text="Native currency of this network"
|
129
|
+
)
|
130
|
+
|
131
|
+
block_explorer_url = models.URLField(
|
132
|
+
blank=True,
|
133
|
+
help_text="Block explorer URL template (use {tx} for transaction hash)"
|
81
134
|
)
|
82
135
|
|
83
|
-
|
84
|
-
|
85
|
-
|
136
|
+
is_active = models.BooleanField(
|
137
|
+
default=True,
|
138
|
+
help_text="Whether this network is available for payments"
|
139
|
+
)
|
140
|
+
|
141
|
+
# Network-specific settings
|
142
|
+
confirmation_blocks = models.PositiveIntegerField(
|
143
|
+
default=1,
|
144
|
+
help_text="Number of confirmations required for this network"
|
145
|
+
)
|
146
|
+
|
147
|
+
average_block_time = models.PositiveIntegerField(
|
148
|
+
default=600, # 10 minutes in seconds
|
149
|
+
help_text="Average block time in seconds"
|
150
|
+
)
|
86
151
|
|
87
152
|
class Meta:
|
88
|
-
db_table = '
|
89
|
-
verbose_name =
|
90
|
-
verbose_name_plural =
|
153
|
+
db_table = 'payments_networks'
|
154
|
+
verbose_name = 'Network'
|
155
|
+
verbose_name_plural = 'Networks'
|
91
156
|
ordering = ['name']
|
157
|
+
indexes = [
|
158
|
+
models.Index(fields=['is_active']),
|
159
|
+
models.Index(fields=['code']),
|
160
|
+
]
|
92
161
|
|
93
162
|
def __str__(self):
|
94
163
|
return f"{self.name} ({self.code})"
|
164
|
+
|
165
|
+
def clean(self):
|
166
|
+
"""Validate network data."""
|
167
|
+
if self.code:
|
168
|
+
self.code = self.code.upper()
|
169
|
+
|
170
|
+
@property
|
171
|
+
def estimated_confirmation_time(self) -> int:
|
172
|
+
"""Estimated time for confirmations in seconds."""
|
173
|
+
return self.confirmation_blocks * self.average_block_time
|
95
174
|
|
96
175
|
|
97
176
|
class ProviderCurrency(TimestampedModel):
|
98
|
-
"""
|
177
|
+
"""
|
178
|
+
Provider-specific currency configuration.
|
99
179
|
|
100
|
-
|
101
|
-
|
180
|
+
Maps currencies to specific providers and networks.
|
181
|
+
"""
|
182
|
+
|
183
|
+
provider = models.CharField(
|
102
184
|
max_length=50,
|
103
|
-
help_text="
|
104
|
-
)
|
105
|
-
provider_currency_code = models.CharField(
|
106
|
-
max_length=20,
|
107
|
-
help_text="Provider code: USDTERC20, USDTBSC, usd"
|
185
|
+
help_text="Payment provider name (e.g., nowpayments)"
|
108
186
|
)
|
109
187
|
|
110
|
-
|
111
|
-
base_currency = models.ForeignKey(
|
188
|
+
currency = models.ForeignKey(
|
112
189
|
Currency,
|
113
190
|
on_delete=models.CASCADE,
|
114
|
-
related_name='
|
115
|
-
help_text="Base currency: BTC, USDT, ETH"
|
191
|
+
related_name='provider_configs'
|
116
192
|
)
|
193
|
+
|
117
194
|
network = models.ForeignKey(
|
118
195
|
Network,
|
119
196
|
on_delete=models.CASCADE,
|
197
|
+
related_name='provider_configs',
|
120
198
|
null=True,
|
121
199
|
blank=True,
|
122
|
-
|
123
|
-
|
200
|
+
help_text="Network for crypto currencies (null for fiat)"
|
201
|
+
)
|
202
|
+
|
203
|
+
# Provider-specific settings
|
204
|
+
provider_currency_code = models.CharField(
|
205
|
+
max_length=20,
|
206
|
+
help_text="Currency code as used by the provider"
|
124
207
|
)
|
125
208
|
|
126
|
-
# Universal provider fields - common across providers
|
127
209
|
min_amount = models.DecimalField(
|
128
210
|
max_digits=20,
|
129
211
|
decimal_places=8,
|
130
212
|
null=True,
|
131
213
|
blank=True,
|
132
|
-
help_text="Minimum payment amount"
|
214
|
+
help_text="Minimum payment amount for this currency"
|
133
215
|
)
|
216
|
+
|
134
217
|
max_amount = models.DecimalField(
|
135
218
|
max_digits=20,
|
136
219
|
decimal_places=8,
|
137
220
|
null=True,
|
138
221
|
blank=True,
|
139
|
-
help_text="Maximum payment amount
|
222
|
+
help_text="Maximum payment amount for this currency"
|
140
223
|
)
|
141
224
|
|
142
|
-
# Status and availability
|
143
225
|
is_enabled = models.BooleanField(
|
144
226
|
default=True,
|
145
|
-
help_text="
|
146
|
-
)
|
147
|
-
available_for_payment = models.BooleanField(
|
148
|
-
default=True,
|
149
|
-
help_text="Can receive payments"
|
150
|
-
)
|
151
|
-
available_for_payout = models.BooleanField(
|
152
|
-
default=True,
|
153
|
-
help_text="Can send payouts"
|
227
|
+
help_text="Whether this currency is enabled for this provider"
|
154
228
|
)
|
155
229
|
|
156
|
-
#
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
)
|
161
|
-
is_stable = models.BooleanField(
|
162
|
-
default=False,
|
163
|
-
help_text="Stable coin (USDT, USDC, etc.)"
|
164
|
-
)
|
165
|
-
priority = models.IntegerField(
|
230
|
+
# Fee configuration
|
231
|
+
fee_percentage = models.DecimalField(
|
232
|
+
max_digits=5,
|
233
|
+
decimal_places=4,
|
166
234
|
default=0,
|
167
|
-
help_text="
|
168
|
-
)
|
169
|
-
logo_url = models.URLField(
|
170
|
-
blank=True,
|
171
|
-
help_text="Currency logo/icon URL from provider"
|
235
|
+
help_text="Fee percentage (0.0250 = 2.5%)"
|
172
236
|
)
|
173
237
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
help_text="
|
238
|
+
fixed_fee = models.DecimalField(
|
239
|
+
max_digits=20,
|
240
|
+
decimal_places=8,
|
241
|
+
default=0,
|
242
|
+
help_text="Fixed fee amount in this currency"
|
179
243
|
)
|
180
244
|
|
181
|
-
# Import manager
|
182
|
-
from ..managers.currency_manager import ProviderCurrencyManager
|
183
|
-
objects = ProviderCurrencyManager()
|
184
|
-
|
185
245
|
class Meta:
|
186
|
-
db_table = '
|
187
|
-
verbose_name =
|
188
|
-
verbose_name_plural =
|
189
|
-
unique_together = [
|
190
|
-
|
191
|
-
|
246
|
+
db_table = 'payments_provider_currencies'
|
247
|
+
verbose_name = 'Provider Currency'
|
248
|
+
verbose_name_plural = 'Provider Currencies'
|
249
|
+
unique_together = [['provider', 'currency', 'network']]
|
250
|
+
ordering = ['provider', 'currency__code']
|
251
|
+
indexes = [
|
252
|
+
models.Index(fields=['provider', 'is_enabled']),
|
253
|
+
models.Index(fields=['currency', 'is_enabled']),
|
192
254
|
]
|
193
|
-
ordering = ['-priority', 'provider_name', 'base_currency__code']
|
194
255
|
|
195
256
|
def __str__(self):
|
196
257
|
network_part = f" ({self.network.code})" if self.network else ""
|
197
|
-
return f"{self.
|
258
|
+
return f"{self.provider}: {self.currency.code}{network_part}"
|
198
259
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
if self.network:
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
def is_amount_valid(self, amount) -> bool:
|
209
|
-
"""Check if amount is within provider limits."""
|
210
|
-
if not amount:
|
211
|
-
return False
|
212
|
-
|
213
|
-
if self.min_amount and amount < self.min_amount:
|
214
|
-
return False
|
215
|
-
|
216
|
-
if self.max_amount and amount > self.max_amount:
|
217
|
-
return False
|
218
|
-
|
219
|
-
return True
|
220
|
-
|
221
|
-
def get_validation_errors(self, amount) -> list:
|
222
|
-
"""Get validation errors for amount."""
|
223
|
-
errors = []
|
260
|
+
def clean(self):
|
261
|
+
"""Validate provider currency configuration."""
|
262
|
+
# Crypto currencies must have a network
|
263
|
+
if self.currency and self.currency.is_crypto and not self.network:
|
264
|
+
raise ValidationError("Crypto currencies must specify a network")
|
265
|
+
|
266
|
+
# Fiat currencies should not have a network
|
267
|
+
if self.currency and self.currency.is_fiat and self.network:
|
268
|
+
raise ValidationError("Fiat currencies should not specify a network")
|
224
269
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
if self.min_amount and amount < self.min_amount:
|
230
|
-
errors.append(f"Amount must be at least {self.min_amount}")
|
231
|
-
|
232
|
-
if self.max_amount and amount > self.max_amount:
|
233
|
-
errors.append(f"Amount must not exceed {self.max_amount}")
|
234
|
-
|
235
|
-
return errors
|
270
|
+
# Validate amount limits
|
271
|
+
if self.min_amount and self.max_amount and self.min_amount > self.max_amount:
|
272
|
+
raise ValidationError("Minimum amount cannot be greater than maximum amount")
|
236
273
|
|
237
274
|
@property
|
238
|
-
def
|
239
|
-
"""
|
240
|
-
|
241
|
-
|
242
|
-
@property
|
243
|
-
def tokens_per_usd(self) -> float:
|
244
|
-
"""Get how many tokens you can buy for 1 USD."""
|
245
|
-
return Currency.objects.get_tokens_per_usd(self.base_currency.code)
|
246
|
-
|
247
|
-
def convert_to_usd(self, amount: float) -> float:
|
248
|
-
"""Convert amount of this currency to USD."""
|
249
|
-
return Currency.objects.convert_to_usd(amount, self.base_currency.code)
|
250
|
-
|
251
|
-
def convert_from_usd(self, usd_amount: float) -> float:
|
252
|
-
"""Convert USD amount to this currency."""
|
253
|
-
return Currency.objects.convert_from_usd(usd_amount, self.base_currency.code)
|
254
|
-
|
275
|
+
def display_name(self) -> str:
|
276
|
+
"""Human-readable display name."""
|
277
|
+
network_part = f" on {self.network.name}" if self.network else ""
|
278
|
+
return f"{self.currency.name}{network_part}"
|
@@ -0,0 +1,44 @@
|
|
1
|
+
"""
|
2
|
+
Django ORM Managers for the Universal Payment System v2.0.
|
3
|
+
|
4
|
+
Optimized managers and querysets for all payment-related models.
|
5
|
+
Follows the data typing requirements: Django ORM for database layer.
|
6
|
+
"""
|
7
|
+
|
8
|
+
# Payment managers
|
9
|
+
from .payment_managers import PaymentQuerySet, PaymentManager
|
10
|
+
|
11
|
+
# Balance managers
|
12
|
+
from .balance_managers import UserBalanceManager, TransactionQuerySet, TransactionManager
|
13
|
+
|
14
|
+
# Subscription managers
|
15
|
+
from .subscription_managers import SubscriptionQuerySet, SubscriptionManager
|
16
|
+
|
17
|
+
# Currency managers
|
18
|
+
from .currency_managers import CurrencyQuerySet, CurrencyManager
|
19
|
+
|
20
|
+
# API Key managers
|
21
|
+
from .api_key_managers import APIKeyQuerySet, APIKeyManager
|
22
|
+
|
23
|
+
__all__ = [
|
24
|
+
# Payment managers
|
25
|
+
'PaymentQuerySet',
|
26
|
+
'PaymentManager',
|
27
|
+
|
28
|
+
# Balance managers
|
29
|
+
'UserBalanceManager',
|
30
|
+
'TransactionQuerySet',
|
31
|
+
'TransactionManager',
|
32
|
+
|
33
|
+
# Subscription managers
|
34
|
+
'SubscriptionQuerySet',
|
35
|
+
'SubscriptionManager',
|
36
|
+
|
37
|
+
# Currency managers
|
38
|
+
'CurrencyQuerySet',
|
39
|
+
'CurrencyManager',
|
40
|
+
|
41
|
+
# API Key managers
|
42
|
+
'APIKeyQuerySet',
|
43
|
+
'APIKeyManager',
|
44
|
+
]
|