django-cfg 1.2.27__py3-none-any.whl → 1.2.31__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/__init__.py +3 -2
- django_cfg/apps/payments/admin/balance_admin.py +18 -18
- django_cfg/apps/payments/admin/currencies_admin.py +319 -131
- django_cfg/apps/payments/admin/payments_admin.py +15 -4
- django_cfg/apps/payments/config/module.py +2 -2
- django_cfg/apps/payments/config/utils.py +2 -2
- django_cfg/apps/payments/decorators.py +2 -2
- django_cfg/apps/payments/management/commands/README.md +95 -127
- django_cfg/apps/payments/management/commands/currency_stats.py +5 -24
- django_cfg/apps/payments/management/commands/manage_currencies.py +229 -0
- django_cfg/apps/payments/management/commands/manage_providers.py +235 -0
- django_cfg/apps/payments/managers/__init__.py +3 -2
- django_cfg/apps/payments/managers/balance_manager.py +2 -2
- django_cfg/apps/payments/managers/currency_manager.py +272 -49
- django_cfg/apps/payments/managers/payment_manager.py +161 -13
- django_cfg/apps/payments/middleware/api_access.py +2 -2
- django_cfg/apps/payments/middleware/rate_limiting.py +8 -18
- django_cfg/apps/payments/middleware/usage_tracking.py +20 -17
- django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +241 -0
- django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +30 -0
- django_cfg/apps/payments/models/__init__.py +3 -2
- django_cfg/apps/payments/models/currencies.py +187 -71
- django_cfg/apps/payments/models/payments.py +3 -2
- django_cfg/apps/payments/serializers/__init__.py +3 -2
- django_cfg/apps/payments/serializers/currencies.py +20 -12
- django_cfg/apps/payments/services/cache/simple_cache.py +2 -2
- django_cfg/apps/payments/services/core/balance_service.py +2 -2
- django_cfg/apps/payments/services/core/fallback_service.py +2 -2
- django_cfg/apps/payments/services/core/payment_service.py +3 -6
- django_cfg/apps/payments/services/core/subscription_service.py +4 -7
- django_cfg/apps/payments/services/internal_types.py +171 -7
- django_cfg/apps/payments/services/monitoring/api_schemas.py +58 -204
- django_cfg/apps/payments/services/monitoring/provider_health.py +2 -2
- django_cfg/apps/payments/services/providers/base.py +144 -43
- django_cfg/apps/payments/services/providers/cryptapi/__init__.py +4 -0
- django_cfg/apps/payments/services/providers/cryptapi/config.py +8 -0
- django_cfg/apps/payments/services/providers/cryptapi/models.py +192 -0
- django_cfg/apps/payments/services/providers/cryptapi/provider.py +439 -0
- django_cfg/apps/payments/services/providers/cryptomus/__init__.py +4 -0
- django_cfg/apps/payments/services/providers/cryptomus/models.py +176 -0
- django_cfg/apps/payments/services/providers/cryptomus/provider.py +429 -0
- django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +564 -0
- django_cfg/apps/payments/services/providers/models/__init__.py +34 -0
- django_cfg/apps/payments/services/providers/models/currencies.py +190 -0
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +4 -0
- django_cfg/apps/payments/services/providers/nowpayments/models.py +196 -0
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +380 -0
- django_cfg/apps/payments/services/providers/registry.py +294 -11
- django_cfg/apps/payments/services/providers/stripe/__init__.py +4 -0
- django_cfg/apps/payments/services/providers/stripe/models.py +184 -0
- django_cfg/apps/payments/services/providers/stripe/provider.py +109 -0
- django_cfg/apps/payments/services/security/error_handler.py +6 -8
- django_cfg/apps/payments/services/security/payment_notifications.py +2 -2
- django_cfg/apps/payments/services/security/webhook_validator.py +3 -4
- django_cfg/apps/payments/signals/api_key_signals.py +2 -2
- django_cfg/apps/payments/signals/payment_signals.py +11 -5
- django_cfg/apps/payments/signals/subscription_signals.py +2 -2
- django_cfg/apps/payments/static/payments/css/payments.css +340 -0
- django_cfg/apps/payments/static/payments/js/notifications.js +202 -0
- django_cfg/apps/payments/static/payments/js/payment-utils.js +318 -0
- django_cfg/apps/payments/static/payments/js/theme.js +86 -0
- django_cfg/apps/payments/tasks/webhook_processing.py +2 -2
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +50 -0
- django_cfg/apps/payments/templates/payments/base.html +182 -0
- django_cfg/apps/payments/templates/payments/components/payment_card.html +201 -0
- django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +109 -0
- django_cfg/apps/payments/templates/payments/components/progress_bar.html +43 -0
- django_cfg/apps/payments/templates/payments/components/provider_stats.html +40 -0
- django_cfg/apps/payments/templates/payments/components/status_badge.html +34 -0
- django_cfg/apps/payments/templates/payments/components/status_overview.html +148 -0
- django_cfg/apps/payments/templates/payments/dashboard.html +258 -0
- django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +35 -0
- django_cfg/apps/payments/templates/payments/payment_create.html +579 -0
- django_cfg/apps/payments/templates/payments/payment_detail.html +373 -0
- django_cfg/apps/payments/templates/payments/payment_list.html +354 -0
- django_cfg/apps/payments/templates/payments/stats.html +261 -0
- django_cfg/apps/payments/templates/payments/test.html +213 -0
- django_cfg/apps/payments/templatetags/__init__.py +1 -0
- django_cfg/apps/payments/templatetags/payments_tags.py +315 -0
- django_cfg/apps/payments/urls.py +3 -1
- django_cfg/apps/payments/urls_admin.py +58 -0
- django_cfg/apps/payments/utils/__init__.py +1 -3
- django_cfg/apps/payments/utils/billing_utils.py +2 -2
- django_cfg/apps/payments/utils/config_utils.py +2 -8
- django_cfg/apps/payments/utils/validation_utils.py +2 -2
- django_cfg/apps/payments/views/__init__.py +3 -2
- django_cfg/apps/payments/views/currency_views.py +31 -20
- django_cfg/apps/payments/views/payment_views.py +2 -2
- django_cfg/apps/payments/views/templates/__init__.py +25 -0
- django_cfg/apps/payments/views/templates/ajax.py +451 -0
- django_cfg/apps/payments/views/templates/base.py +212 -0
- django_cfg/apps/payments/views/templates/dashboard.py +60 -0
- django_cfg/apps/payments/views/templates/payment_detail.py +102 -0
- django_cfg/apps/payments/views/templates/payment_management.py +158 -0
- django_cfg/apps/payments/views/templates/qr_code.py +174 -0
- django_cfg/apps/payments/views/templates/stats.py +244 -0
- django_cfg/apps/payments/views/templates/utils.py +181 -0
- django_cfg/apps/payments/views/webhook_views.py +2 -2
- django_cfg/apps/payments/viewsets.py +3 -2
- django_cfg/apps/tasks/urls.py +0 -2
- django_cfg/apps/tasks/urls_admin.py +14 -0
- django_cfg/apps/urls.py +6 -3
- django_cfg/core/config.py +35 -0
- django_cfg/models/payments.py +2 -8
- django_cfg/modules/django_currency/__init__.py +16 -11
- django_cfg/modules/django_currency/clients/__init__.py +4 -4
- django_cfg/modules/django_currency/clients/coinpaprika_client.py +289 -0
- django_cfg/modules/django_currency/clients/yahoo_client.py +157 -0
- django_cfg/modules/django_currency/core/__init__.py +1 -7
- django_cfg/modules/django_currency/core/converter.py +18 -23
- django_cfg/modules/django_currency/core/models.py +122 -11
- django_cfg/modules/django_currency/database/__init__.py +4 -4
- django_cfg/modules/django_currency/database/database_loader.py +190 -309
- django_cfg/modules/django_unfold/dashboard.py +7 -2
- django_cfg/registry/core.py +1 -0
- django_cfg/template_archive/.gitignore +1 -0
- django_cfg/template_archive/django_sample.zip +0 -0
- django_cfg/templates/admin/components/action_grid.html +9 -9
- django_cfg/templates/admin/components/metric_card.html +5 -5
- django_cfg/templates/admin/components/status_badge.html +2 -2
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +152 -24
- django_cfg/templates/admin/snippets/components/quick_actions.html +3 -3
- django_cfg/templates/admin/snippets/components/system_health.html +1 -1
- django_cfg/templates/admin/snippets/tabs/overview_tab.html +49 -52
- {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/METADATA +13 -18
- {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/RECORD +130 -83
- django_cfg/apps/payments/management/commands/populate_currencies.py +0 -246
- django_cfg/apps/payments/management/commands/update_currencies.py +0 -336
- django_cfg/apps/payments/services/providers/cryptapi.py +0 -273
- django_cfg/apps/payments/services/providers/cryptomus.py +0 -310
- django_cfg/apps/payments/services/providers/nowpayments.py +0 -293
- django_cfg/apps/payments/services/validators/__init__.py +0 -8
- django_cfg/modules/django_currency/clients/coingecko_client.py +0 -257
- django_cfg/modules/django_currency/clients/yfinance_client.py +0 -246
- {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/WHEEL +0 -0
- {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.2.27.dist-info → django_cfg-1.2.31.dist-info}/licenses/LICENSE +0 -0
@@ -1,138 +1,254 @@
|
|
1
1
|
"""
|
2
|
-
Currency models for the universal payments system.
|
2
|
+
Currency models for the universal payments system - KISS version.
|
3
3
|
"""
|
4
4
|
|
5
5
|
from django.db import models
|
6
6
|
from .base import TimestampedModel
|
7
7
|
|
8
|
+
# Currency converter import moved inside methods to avoid circular imports
|
8
9
|
|
9
10
|
class Currency(TimestampedModel):
|
10
|
-
"""
|
11
|
+
"""Base currencies - clean, no provider-specific codes."""
|
11
12
|
|
12
13
|
class CurrencyType(models.TextChoices):
|
13
14
|
FIAT = "fiat", "Fiat Currency"
|
14
15
|
CRYPTO = "crypto", "Cryptocurrency"
|
15
16
|
|
17
|
+
# Core fields - only essentials
|
16
18
|
code = models.CharField(
|
17
19
|
max_length=10,
|
18
20
|
unique=True,
|
19
|
-
help_text="
|
21
|
+
help_text="Clean currency code: BTC, USDT, ETH, USD (NO network suffixes)"
|
20
22
|
)
|
21
23
|
name = models.CharField(
|
22
24
|
max_length=100,
|
23
|
-
help_text="
|
24
|
-
)
|
25
|
-
symbol = models.CharField(
|
26
|
-
max_length=10,
|
27
|
-
help_text="Currency symbol (e.g., $, ₿, Ξ)"
|
25
|
+
help_text="Currency name: Bitcoin, Tether USD, Ethereum"
|
28
26
|
)
|
29
27
|
currency_type = models.CharField(
|
30
28
|
max_length=10,
|
31
29
|
choices=CurrencyType.choices,
|
32
|
-
help_text="
|
33
|
-
)
|
34
|
-
decimal_places = models.PositiveSmallIntegerField(
|
35
|
-
default=2,
|
36
|
-
help_text="Number of decimal places for this currency"
|
37
|
-
)
|
38
|
-
is_active = models.BooleanField(
|
39
|
-
default=True,
|
40
|
-
help_text="Whether this currency is active for payments"
|
41
|
-
)
|
42
|
-
min_payment_amount = models.FloatField(
|
43
|
-
default=1.0,
|
44
|
-
help_text="Minimum payment amount for this currency"
|
30
|
+
help_text="fiat or crypto"
|
45
31
|
)
|
46
32
|
|
47
|
-
#
|
48
|
-
usd_rate = models.
|
49
|
-
|
50
|
-
|
33
|
+
# USD rate caching - updated once per day
|
34
|
+
usd_rate = models.DecimalField(
|
35
|
+
max_digits=20,
|
36
|
+
decimal_places=8,
|
37
|
+
null=True,
|
38
|
+
blank=True,
|
39
|
+
help_text="Cached USD exchange rate (1 CURRENCY = X USD)"
|
51
40
|
)
|
41
|
+
|
52
42
|
rate_updated_at = models.DateTimeField(
|
53
43
|
null=True,
|
54
44
|
blank=True,
|
55
|
-
help_text="When the
|
45
|
+
help_text="When the USD rate was last updated"
|
56
46
|
)
|
57
47
|
|
58
|
-
# Import
|
59
|
-
from ..managers import CurrencyManager
|
48
|
+
# Import manager
|
49
|
+
from ..managers.currency_manager import CurrencyManager
|
60
50
|
objects = CurrencyManager()
|
61
51
|
|
62
52
|
class Meta:
|
63
53
|
db_table = 'payment_currencies'
|
64
54
|
verbose_name = "Currency"
|
65
55
|
verbose_name_plural = "Currencies"
|
66
|
-
|
67
|
-
models.Index(fields=['code']),
|
68
|
-
models.Index(fields=['currency_type']),
|
69
|
-
models.Index(fields=['is_active']),
|
70
|
-
]
|
71
|
-
ordering = ['code']
|
56
|
+
ordering = ['currency_type', 'code']
|
72
57
|
|
73
58
|
def __str__(self):
|
74
59
|
return f"{self.code} - {self.name}"
|
75
60
|
|
76
61
|
@property
|
77
62
|
def is_fiat(self) -> bool:
|
78
|
-
"""Check if this is a fiat currency."""
|
79
63
|
return self.currency_type == self.CurrencyType.FIAT
|
80
64
|
|
81
65
|
@property
|
82
66
|
def is_crypto(self) -> bool:
|
83
|
-
"""Check if this is a cryptocurrency."""
|
84
67
|
return self.currency_type == self.CurrencyType.CRYPTO
|
68
|
+
|
69
|
+
|
70
|
+
class Network(TimestampedModel):
|
71
|
+
"""Blockchain networks - code and name only."""
|
85
72
|
|
86
|
-
|
87
|
-
|
88
|
-
|
73
|
+
code = models.CharField(
|
74
|
+
max_length=20,
|
75
|
+
unique=True,
|
76
|
+
help_text="Network code: ethereum, bitcoin, tron, bsc"
|
77
|
+
)
|
78
|
+
name = models.CharField(
|
79
|
+
max_length=100,
|
80
|
+
help_text="Network name: Ethereum, Bitcoin, TRON, BSC"
|
81
|
+
)
|
89
82
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
83
|
+
# Import manager
|
84
|
+
from ..managers.currency_manager import NetworkManager
|
85
|
+
objects = NetworkManager()
|
86
|
+
|
87
|
+
class Meta:
|
88
|
+
db_table = 'payment_networks'
|
89
|
+
verbose_name = "Network"
|
90
|
+
verbose_name_plural = "Networks"
|
91
|
+
ordering = ['name']
|
92
|
+
|
93
|
+
def __str__(self):
|
94
|
+
return f"{self.name} ({self.code})"
|
95
95
|
|
96
96
|
|
97
|
-
class
|
98
|
-
"""
|
97
|
+
class ProviderCurrency(TimestampedModel):
|
98
|
+
"""Provider-currency-network mapping - minimal."""
|
99
99
|
|
100
|
-
|
100
|
+
# Identification
|
101
|
+
provider_name = models.CharField(
|
102
|
+
max_length=50,
|
103
|
+
help_text="Provider: nowpayments, stripe, cryptomus"
|
104
|
+
)
|
105
|
+
provider_currency_code = models.CharField(
|
106
|
+
max_length=20,
|
107
|
+
help_text="Provider code: USDTERC20, USDTBSC, usd"
|
108
|
+
)
|
109
|
+
|
110
|
+
# Links to clean models
|
111
|
+
base_currency = models.ForeignKey(
|
101
112
|
Currency,
|
102
113
|
on_delete=models.CASCADE,
|
103
|
-
related_name='
|
104
|
-
help_text="
|
114
|
+
related_name='provider_mappings',
|
115
|
+
help_text="Base currency: BTC, USDT, ETH"
|
105
116
|
)
|
106
|
-
|
107
|
-
|
108
|
-
|
117
|
+
network = models.ForeignKey(
|
118
|
+
Network,
|
119
|
+
on_delete=models.CASCADE,
|
120
|
+
null=True,
|
121
|
+
blank=True,
|
122
|
+
related_name='provider_currencies',
|
123
|
+
help_text="Network for crypto (null for fiat)"
|
109
124
|
)
|
110
|
-
|
111
|
-
|
112
|
-
|
125
|
+
|
126
|
+
# Universal provider fields - common across providers
|
127
|
+
min_amount = models.DecimalField(
|
128
|
+
max_digits=20,
|
129
|
+
decimal_places=8,
|
130
|
+
null=True,
|
131
|
+
blank=True,
|
132
|
+
help_text="Minimum payment amount"
|
113
133
|
)
|
114
|
-
|
134
|
+
max_amount = models.DecimalField(
|
135
|
+
max_digits=20,
|
136
|
+
decimal_places=8,
|
137
|
+
null=True,
|
138
|
+
blank=True,
|
139
|
+
help_text="Maximum payment amount (null = no limit)"
|
140
|
+
)
|
141
|
+
|
142
|
+
# Status and availability
|
143
|
+
is_enabled = models.BooleanField(
|
115
144
|
default=True,
|
116
|
-
help_text="
|
145
|
+
help_text="Enabled by provider"
|
117
146
|
)
|
118
|
-
|
119
|
-
default=
|
120
|
-
help_text="
|
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"
|
121
154
|
)
|
122
155
|
|
123
|
-
#
|
124
|
-
|
125
|
-
|
156
|
+
# Classification for UI
|
157
|
+
is_popular = models.BooleanField(
|
158
|
+
default=False,
|
159
|
+
help_text="Popular/recommended by provider"
|
160
|
+
)
|
161
|
+
is_stable = models.BooleanField(
|
162
|
+
default=False,
|
163
|
+
help_text="Stable coin (USDT, USDC, etc.)"
|
164
|
+
)
|
165
|
+
priority = models.IntegerField(
|
166
|
+
default=0,
|
167
|
+
help_text="Display priority (higher = shown first)"
|
168
|
+
)
|
169
|
+
logo_url = models.URLField(
|
170
|
+
blank=True,
|
171
|
+
help_text="Currency logo/icon URL from provider"
|
172
|
+
)
|
173
|
+
|
174
|
+
# Raw provider data - everything else goes here
|
175
|
+
metadata = models.JSONField(
|
176
|
+
default=dict,
|
177
|
+
blank=True,
|
178
|
+
help_text="All provider-specific data: logo_url, smart_contract, wallet_regex, commission_percent, etc."
|
179
|
+
)
|
180
|
+
|
181
|
+
# Import manager
|
182
|
+
from ..managers.currency_manager import ProviderCurrencyManager
|
183
|
+
objects = ProviderCurrencyManager()
|
126
184
|
|
127
185
|
class Meta:
|
128
|
-
db_table = '
|
129
|
-
verbose_name = "Currency
|
130
|
-
verbose_name_plural = "
|
131
|
-
unique_together = [
|
132
|
-
|
133
|
-
|
134
|
-
models.Index(fields=['network_code']),
|
186
|
+
db_table = 'payment_provider_currencies'
|
187
|
+
verbose_name = "Provider Currency"
|
188
|
+
verbose_name_plural = "Provider Currencies"
|
189
|
+
unique_together = [
|
190
|
+
('provider_name', 'provider_currency_code'),
|
191
|
+
('provider_name', 'base_currency', 'network')
|
135
192
|
]
|
193
|
+
ordering = ['-priority', 'provider_name', 'base_currency__code']
|
136
194
|
|
137
195
|
def __str__(self):
|
138
|
-
|
196
|
+
network_part = f" ({self.network.code})" if self.network else ""
|
197
|
+
return f"{self.provider_name}: {self.base_currency.code}{network_part}"
|
198
|
+
|
199
|
+
@property
|
200
|
+
def display_name(self) -> str:
|
201
|
+
"""Human-readable name."""
|
202
|
+
if self.network:
|
203
|
+
return f"{self.base_currency.name} ({self.network.name})"
|
204
|
+
return self.base_currency.name
|
205
|
+
|
206
|
+
# Metadata helper properties
|
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 = []
|
224
|
+
|
225
|
+
if not amount:
|
226
|
+
errors.append("Amount is required")
|
227
|
+
return errors
|
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
|
236
|
+
|
237
|
+
@property
|
238
|
+
def usd_rate(self) -> float:
|
239
|
+
"""Get USD rate for base currency (1 CURRENCY = X USD)."""
|
240
|
+
return Currency.objects.get_usd_rate(self.base_currency.code)
|
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
|
+
|
@@ -13,6 +13,7 @@ User = get_user_model()
|
|
13
13
|
|
14
14
|
|
15
15
|
|
16
|
+
|
16
17
|
class UniversalPayment(UUIDTimestampedModel):
|
17
18
|
"""Universal payment model for all providers."""
|
18
19
|
|
@@ -208,8 +209,8 @@ class UniversalPayment(UUIDTimestampedModel):
|
|
208
209
|
help_text="When the payment was processed and funds added to balance"
|
209
210
|
)
|
210
211
|
|
211
|
-
#
|
212
|
-
from ..managers import UniversalPaymentManager
|
212
|
+
# Custom managers for optimized queries
|
213
|
+
from ..managers.payment_manager import UniversalPaymentManager
|
213
214
|
objects = UniversalPaymentManager()
|
214
215
|
|
215
216
|
class Meta:
|
@@ -16,7 +16,7 @@ from .api_keys import (
|
|
16
16
|
APIKeySerializer, APIKeyCreateSerializer, APIKeyListSerializer
|
17
17
|
)
|
18
18
|
from .currencies import (
|
19
|
-
CurrencySerializer,
|
19
|
+
CurrencySerializer, NetworkSerializer, ProviderCurrencySerializer, CurrencyListSerializer
|
20
20
|
)
|
21
21
|
from .tariffs import (
|
22
22
|
TariffSerializer, TariffEndpointGroupSerializer, TariffListSerializer
|
@@ -46,7 +46,8 @@ __all__ = [
|
|
46
46
|
|
47
47
|
# Currencies
|
48
48
|
'CurrencySerializer',
|
49
|
-
'
|
49
|
+
'NetworkSerializer',
|
50
|
+
'ProviderCurrencySerializer',
|
50
51
|
'CurrencyListSerializer',
|
51
52
|
|
52
53
|
# Tariffs
|
@@ -3,7 +3,7 @@ Currency serializers.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
from rest_framework import serializers
|
6
|
-
from ..models import Currency,
|
6
|
+
from ..models import Currency, Network, ProviderCurrency
|
7
7
|
|
8
8
|
|
9
9
|
class CurrencySerializer(serializers.ModelSerializer):
|
@@ -16,9 +16,8 @@ class CurrencySerializer(serializers.ModelSerializer):
|
|
16
16
|
class Meta:
|
17
17
|
model = Currency
|
18
18
|
fields = [
|
19
|
-
'id', 'code', 'name', '
|
20
|
-
'is_crypto', 'is_fiat', '
|
21
|
-
'is_active', 'min_payment_amount'
|
19
|
+
'id', 'code', 'name', 'currency_type', 'currency_type_display',
|
20
|
+
'is_crypto', 'is_fiat', 'usd_rate', 'rate_updated_at'
|
22
21
|
]
|
23
22
|
read_only_fields = ['rate_updated_at']
|
24
23
|
|
@@ -31,17 +30,26 @@ class CurrencySerializer(serializers.ModelSerializer):
|
|
31
30
|
return obj.is_fiat
|
32
31
|
|
33
32
|
|
34
|
-
class
|
35
|
-
"""
|
33
|
+
class NetworkSerializer(serializers.ModelSerializer):
|
34
|
+
"""Network information."""
|
36
35
|
|
37
|
-
|
38
|
-
|
36
|
+
class Meta:
|
37
|
+
model = Network
|
38
|
+
fields = ['id', 'code', 'name']
|
39
|
+
|
40
|
+
|
41
|
+
class ProviderCurrencySerializer(serializers.ModelSerializer):
|
42
|
+
"""Provider currency with base currency and network info."""
|
43
|
+
|
44
|
+
base_currency = CurrencySerializer(read_only=True)
|
45
|
+
network = NetworkSerializer(read_only=True)
|
39
46
|
|
40
47
|
class Meta:
|
41
|
-
model =
|
48
|
+
model = ProviderCurrency
|
42
49
|
fields = [
|
43
|
-
'id', '
|
44
|
-
'
|
50
|
+
'id', 'provider_name', 'provider_currency_code', 'base_currency', 'network',
|
51
|
+
'is_enabled', 'available_for_payment', 'available_for_payout',
|
52
|
+
'is_popular', 'is_stable', 'min_amount', 'max_amount', 'logo_url'
|
45
53
|
]
|
46
54
|
|
47
55
|
|
@@ -52,4 +60,4 @@ class CurrencyListSerializer(serializers.ModelSerializer):
|
|
52
60
|
|
53
61
|
class Meta:
|
54
62
|
model = Currency
|
55
|
-
fields = ['id', 'code', 'name', 'currency_type', 'currency_type_display'
|
63
|
+
fields = ['id', 'code', 'name', 'currency_type', 'currency_type_display']
|
@@ -3,14 +3,14 @@ Simple cache implementation for API keys and rate limiting.
|
|
3
3
|
ONLY for API access control - NOT payment data!
|
4
4
|
"""
|
5
5
|
|
6
|
-
import
|
6
|
+
from django_cfg.modules.django_logger import get_logger
|
7
7
|
from typing import Optional, Any
|
8
8
|
from django.core.cache import cache
|
9
9
|
|
10
10
|
from .base import CacheInterface
|
11
11
|
from ...utils.config_utils import CacheConfigHelper
|
12
12
|
|
13
|
-
logger =
|
13
|
+
logger = get_logger("simple_cache")
|
14
14
|
|
15
15
|
|
16
16
|
class SimpleCache(CacheInterface):
|
@@ -5,8 +5,8 @@ This service handles user balance operations, transaction recording,
|
|
5
5
|
and balance validation with atomic operations.
|
6
6
|
"""
|
7
7
|
|
8
|
-
import logging
|
9
8
|
from typing import Dict, Any, Optional, List
|
9
|
+
from django_cfg.modules.django_logger import get_logger
|
10
10
|
from decimal import Decimal
|
11
11
|
from datetime import timezone
|
12
12
|
|
@@ -18,7 +18,7 @@ from ...models import UserBalance, Transaction
|
|
18
18
|
from ..internal_types import ServiceOperationResult, BalanceUpdateRequest, UserBalanceResult, TransactionInfo
|
19
19
|
|
20
20
|
User = get_user_model()
|
21
|
-
logger =
|
21
|
+
logger = get_logger("balance_service")
|
22
22
|
|
23
23
|
|
24
24
|
class BalanceOperation(BaseModel):
|
@@ -5,7 +5,7 @@ Handles automatic provider switching when providers become unavailable,
|
|
5
5
|
ensuring payment system resilience and high availability.
|
6
6
|
"""
|
7
7
|
|
8
|
-
import
|
8
|
+
from django_cfg.modules.django_logger import get_logger
|
9
9
|
from typing import Optional, List, Dict, Any
|
10
10
|
from dataclasses import dataclass
|
11
11
|
from enum import Enum
|
@@ -18,7 +18,7 @@ from ..monitoring.provider_health import get_health_monitor, HealthStatus
|
|
18
18
|
from ..providers.registry import ProviderRegistry
|
19
19
|
from ...models.events import PaymentEvent
|
20
20
|
|
21
|
-
logger =
|
21
|
+
logger = get_logger("fallback_service")
|
22
22
|
|
23
23
|
|
24
24
|
class FallbackStrategy(Enum):
|
@@ -5,7 +5,6 @@ This service handles universal payment operations, provider orchestration,
|
|
5
5
|
and payment lifecycle management.
|
6
6
|
"""
|
7
7
|
|
8
|
-
import logging
|
9
8
|
from typing import Optional, List
|
10
9
|
from decimal import Decimal
|
11
10
|
from django.db import transaction
|
@@ -18,6 +17,7 @@ from .fallback_service import get_fallback_service
|
|
18
17
|
from ...models import UniversalPayment, UserBalance, Transaction
|
19
18
|
from ...utils.config_utils import get_payments_config
|
20
19
|
from ..providers.registry import ProviderRegistry
|
20
|
+
from django_cfg.modules.django_logger import get_logger
|
21
21
|
from ..monitoring.provider_health import get_health_monitor
|
22
22
|
from ..internal_types import (
|
23
23
|
ProviderResponse, WebhookData, ServiceOperationResult,
|
@@ -28,9 +28,10 @@ from ..internal_types import (
|
|
28
28
|
|
29
29
|
# Import django_currency module for currency conversion
|
30
30
|
from django_cfg.modules.django_currency import convert_currency, CurrencyError
|
31
|
+
from ...models.events import PaymentEvent
|
31
32
|
|
32
33
|
User = get_user_model()
|
33
|
-
logger =
|
34
|
+
logger = get_logger("payment_service")
|
34
35
|
|
35
36
|
|
36
37
|
class PaymentRequest(BaseModel):
|
@@ -501,8 +502,6 @@ class PaymentService:
|
|
501
502
|
data: Event data
|
502
503
|
"""
|
503
504
|
try:
|
504
|
-
from ...models.events import PaymentEvent
|
505
|
-
|
506
505
|
# Get next sequence number
|
507
506
|
last_event = PaymentEvent.objects.filter(
|
508
507
|
payment_id=str(payment.id)
|
@@ -534,8 +533,6 @@ class PaymentService:
|
|
534
533
|
List of payment events
|
535
534
|
"""
|
536
535
|
try:
|
537
|
-
from ...models.events import PaymentEvent
|
538
|
-
|
539
536
|
events = PaymentEvent.objects.filter(
|
540
537
|
payment_id=payment_id
|
541
538
|
).order_by('sequence_number')
|
@@ -5,21 +5,21 @@ This service handles subscription creation, renewal, access validation,
|
|
5
5
|
and usage tracking with Redis caching.
|
6
6
|
"""
|
7
7
|
|
8
|
-
import logging
|
9
8
|
from typing import Dict, Any, Optional, List
|
9
|
+
from django_cfg.modules.django_logger import get_logger
|
10
10
|
from datetime import datetime, timedelta, timezone as dt_timezone
|
11
11
|
|
12
12
|
from django.db import transaction
|
13
13
|
from django.contrib.auth import get_user_model
|
14
14
|
from django.utils import timezone
|
15
15
|
from pydantic import BaseModel, Field, ValidationError
|
16
|
-
|
16
|
+
from decimal import Decimal
|
17
17
|
|
18
18
|
from ...models import Subscription, EndpointGroup, Tariff
|
19
|
-
from ..internal_types import ServiceOperationResult
|
19
|
+
from ..internal_types import ServiceOperationResult, SubscriptionInfo, EndpointGroupInfo
|
20
20
|
|
21
21
|
User = get_user_model()
|
22
|
-
logger =
|
22
|
+
logger = get_logger("subscription_service")
|
23
23
|
|
24
24
|
|
25
25
|
class SubscriptionRequest(BaseModel):
|
@@ -276,9 +276,6 @@ class SubscriptionService:
|
|
276
276
|
'endpoint_group'
|
277
277
|
).order_by('-created_at')
|
278
278
|
|
279
|
-
from ..internal_types import SubscriptionInfo, EndpointGroupInfo
|
280
|
-
from decimal import Decimal
|
281
|
-
|
282
279
|
result = [
|
283
280
|
SubscriptionInfo(
|
284
281
|
id=str(sub.id),
|