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.
Files changed (256) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/api/health/views.py +4 -2
  3. django_cfg/apps/knowbase/config/settings.py +16 -15
  4. django_cfg/apps/payments/README.md +326 -0
  5. django_cfg/apps/payments/admin/__init__.py +20 -10
  6. django_cfg/apps/payments/admin/api_keys_admin.py +521 -237
  7. django_cfg/apps/payments/admin/balance_admin.py +592 -297
  8. django_cfg/apps/payments/admin/currencies_admin.py +526 -222
  9. django_cfg/apps/payments/admin/filters.py +306 -199
  10. django_cfg/apps/payments/admin/payments_admin.py +465 -70
  11. django_cfg/apps/payments/admin/subscriptions_admin.py +578 -128
  12. django_cfg/apps/payments/admin_interface/__init__.py +18 -0
  13. django_cfg/apps/payments/admin_interface/templates/payments/base.html +162 -0
  14. django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +38 -0
  15. django_cfg/apps/payments/admin_interface/templates/payments/components/loading_spinner.html +16 -0
  16. django_cfg/apps/payments/admin_interface/templates/payments/components/notification.html +27 -0
  17. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_card.html +86 -0
  18. django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +39 -0
  19. django_cfg/apps/payments/admin_interface/templates/payments/currency_converter.html +382 -0
  20. django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +300 -0
  21. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +303 -0
  22. django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +382 -0
  23. django_cfg/apps/payments/admin_interface/templates/payments/payment_status.html +500 -0
  24. django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +594 -0
  25. django_cfg/apps/payments/admin_interface/views/__init__.py +23 -0
  26. django_cfg/apps/payments/admin_interface/views/payment_views.py +259 -0
  27. django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +37 -0
  28. django_cfg/apps/payments/apps.py +34 -9
  29. django_cfg/apps/payments/config/__init__.py +28 -51
  30. django_cfg/apps/payments/config/constance/__init__.py +22 -0
  31. django_cfg/apps/payments/config/constance/config_service.py +123 -0
  32. django_cfg/apps/payments/config/constance/fields.py +69 -0
  33. django_cfg/apps/payments/config/constance/settings.py +160 -0
  34. django_cfg/apps/payments/config/django_cfg_integration.py +202 -0
  35. django_cfg/apps/payments/config/helpers.py +130 -0
  36. django_cfg/apps/payments/management/__init__.py +1 -3
  37. django_cfg/apps/payments/management/commands/__init__.py +1 -3
  38. django_cfg/apps/payments/management/commands/manage_currencies.py +303 -151
  39. django_cfg/apps/payments/management/commands/manage_providers.py +333 -160
  40. django_cfg/apps/payments/middleware/__init__.py +3 -1
  41. django_cfg/apps/payments/middleware/api_access.py +329 -222
  42. django_cfg/apps/payments/middleware/rate_limiting.py +342 -152
  43. django_cfg/apps/payments/middleware/usage_tracking.py +249 -240
  44. django_cfg/apps/payments/migrations/0001_initial.py +708 -536
  45. django_cfg/apps/payments/models/__init__.py +13 -18
  46. django_cfg/apps/payments/models/api_keys.py +121 -43
  47. django_cfg/apps/payments/models/balance.py +150 -115
  48. django_cfg/apps/payments/models/base.py +68 -15
  49. django_cfg/apps/payments/models/currencies.py +172 -148
  50. django_cfg/apps/payments/models/managers/__init__.py +44 -0
  51. django_cfg/apps/payments/models/managers/api_key_managers.py +329 -0
  52. django_cfg/apps/payments/models/managers/balance_managers.py +599 -0
  53. django_cfg/apps/payments/models/managers/currency_managers.py +385 -0
  54. django_cfg/apps/payments/models/managers/payment_managers.py +511 -0
  55. django_cfg/apps/payments/models/managers/subscription_managers.py +641 -0
  56. django_cfg/apps/payments/models/payments.py +235 -285
  57. django_cfg/apps/payments/models/subscriptions.py +257 -177
  58. django_cfg/apps/payments/models/tariffs.py +147 -40
  59. django_cfg/apps/payments/services/__init__.py +209 -56
  60. django_cfg/apps/payments/services/cache/__init__.py +6 -6
  61. django_cfg/apps/payments/services/cache/{simple_cache.py → cache_service.py} +112 -12
  62. django_cfg/apps/payments/services/core/__init__.py +10 -6
  63. django_cfg/apps/payments/services/core/balance_service.py +435 -360
  64. django_cfg/apps/payments/services/core/base.py +166 -0
  65. django_cfg/apps/payments/services/core/currency_service.py +478 -0
  66. django_cfg/apps/payments/services/core/payment_service.py +346 -467
  67. django_cfg/apps/payments/services/core/subscription_service.py +425 -481
  68. django_cfg/apps/payments/services/core/webhook_service.py +410 -0
  69. django_cfg/apps/payments/services/integrations/__init__.py +29 -0
  70. django_cfg/apps/payments/services/integrations/ngrok_service.py +47 -0
  71. django_cfg/apps/payments/services/integrations/providers_config.py +107 -0
  72. django_cfg/apps/payments/services/providers/__init__.py +9 -14
  73. django_cfg/apps/payments/services/providers/base.py +234 -174
  74. django_cfg/apps/payments/services/providers/nowpayments.py +478 -0
  75. django_cfg/apps/payments/services/providers/registry.py +367 -301
  76. django_cfg/apps/payments/services/types/__init__.py +78 -0
  77. django_cfg/apps/payments/services/types/data.py +177 -0
  78. django_cfg/apps/payments/services/types/requests.py +150 -0
  79. django_cfg/apps/payments/services/types/responses.py +156 -0
  80. django_cfg/apps/payments/services/types/webhooks.py +232 -0
  81. django_cfg/apps/payments/signals/__init__.py +33 -8
  82. django_cfg/apps/payments/signals/api_key_signals.py +210 -129
  83. django_cfg/apps/payments/signals/balance_signals.py +174 -0
  84. django_cfg/apps/payments/signals/payment_signals.py +128 -103
  85. django_cfg/apps/payments/signals/subscription_signals.py +194 -142
  86. django_cfg/apps/payments/static/payments/css/components.css +380 -0
  87. django_cfg/apps/payments/static/payments/css/dashboard.css +188 -0
  88. django_cfg/apps/payments/static/payments/js/components.js +545 -0
  89. django_cfg/apps/payments/static/payments/js/utils.js +412 -0
  90. django_cfg/apps/payments/templatetags/__init__.py +1 -1
  91. django_cfg/apps/payments/templatetags/payment_tags.py +466 -0
  92. django_cfg/apps/payments/urls.py +45 -48
  93. django_cfg/apps/payments/urls_admin.py +33 -42
  94. django_cfg/apps/payments/views/api/__init__.py +101 -0
  95. django_cfg/apps/payments/views/api/api_keys.py +387 -0
  96. django_cfg/apps/payments/views/api/balances.py +381 -0
  97. django_cfg/apps/payments/views/api/base.py +298 -0
  98. django_cfg/apps/payments/views/api/currencies.py +402 -0
  99. django_cfg/apps/payments/views/api/payments.py +415 -0
  100. django_cfg/apps/payments/views/api/subscriptions.py +475 -0
  101. django_cfg/apps/payments/views/api/webhooks.py +476 -0
  102. django_cfg/apps/payments/views/serializers/__init__.py +99 -0
  103. django_cfg/apps/payments/views/serializers/api_keys.py +424 -0
  104. django_cfg/apps/payments/views/serializers/balances.py +300 -0
  105. django_cfg/apps/payments/views/serializers/currencies.py +335 -0
  106. django_cfg/apps/payments/views/serializers/payments.py +387 -0
  107. django_cfg/apps/payments/views/serializers/subscriptions.py +429 -0
  108. django_cfg/apps/payments/views/serializers/webhooks.py +137 -0
  109. django_cfg/config.py +1 -1
  110. django_cfg/core/config.py +40 -4
  111. django_cfg/core/generation.py +25 -4
  112. django_cfg/core/integration/README.md +363 -0
  113. django_cfg/core/integration/__init__.py +47 -0
  114. django_cfg/core/integration/commands_collector.py +239 -0
  115. django_cfg/core/integration/display/__init__.py +15 -0
  116. django_cfg/core/integration/display/base.py +157 -0
  117. django_cfg/core/integration/display/ngrok.py +164 -0
  118. django_cfg/core/integration/display/startup.py +815 -0
  119. django_cfg/core/integration/url_integration.py +123 -0
  120. django_cfg/core/integration/version_checker.py +160 -0
  121. django_cfg/management/commands/auto_generate.py +4 -0
  122. django_cfg/management/commands/check_settings.py +6 -0
  123. django_cfg/management/commands/clear_constance.py +5 -2
  124. django_cfg/management/commands/create_token.py +6 -0
  125. django_cfg/management/commands/list_urls.py +6 -0
  126. django_cfg/management/commands/migrate_all.py +6 -0
  127. django_cfg/management/commands/migrator.py +3 -0
  128. django_cfg/management/commands/rundramatiq.py +6 -0
  129. django_cfg/management/commands/runserver_ngrok.py +51 -29
  130. django_cfg/management/commands/script.py +6 -0
  131. django_cfg/management/commands/show_config.py +12 -2
  132. django_cfg/management/commands/show_urls.py +4 -0
  133. django_cfg/management/commands/superuser.py +6 -0
  134. django_cfg/management/commands/task_clear.py +4 -1
  135. django_cfg/management/commands/task_status.py +3 -1
  136. django_cfg/management/commands/test_email.py +3 -0
  137. django_cfg/management/commands/test_telegram.py +6 -0
  138. django_cfg/management/commands/test_twilio.py +6 -0
  139. django_cfg/management/commands/tree.py +6 -0
  140. django_cfg/management/commands/validate_config.py +155 -149
  141. django_cfg/models/constance.py +31 -11
  142. django_cfg/models/payments.py +175 -492
  143. django_cfg/modules/django_logger.py +160 -146
  144. django_cfg/modules/django_unfold/dashboard.py +64 -16
  145. django_cfg/registry/core.py +1 -0
  146. django_cfg/template_archive/django_sample.zip +0 -0
  147. django_cfg/utils/smart_defaults.py +222 -571
  148. django_cfg/utils/toolkit.py +51 -11
  149. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/METADATA +4 -1
  150. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/RECORD +153 -185
  151. django_cfg/apps/payments/__init__.py +0 -8
  152. django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
  153. django_cfg/apps/payments/config/module.py +0 -70
  154. django_cfg/apps/payments/config/providers.py +0 -105
  155. django_cfg/apps/payments/config/settings.py +0 -96
  156. django_cfg/apps/payments/config/utils.py +0 -52
  157. django_cfg/apps/payments/decorators.py +0 -291
  158. django_cfg/apps/payments/management/commands/README.md +0 -146
  159. django_cfg/apps/payments/management/commands/currency_stats.py +0 -304
  160. django_cfg/apps/payments/managers/__init__.py +0 -23
  161. django_cfg/apps/payments/managers/api_key_manager.py +0 -35
  162. django_cfg/apps/payments/managers/balance_manager.py +0 -361
  163. django_cfg/apps/payments/managers/currency_manager.py +0 -306
  164. django_cfg/apps/payments/managers/payment_manager.py +0 -192
  165. django_cfg/apps/payments/managers/subscription_manager.py +0 -37
  166. django_cfg/apps/payments/managers/tariff_manager.py +0 -29
  167. django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +0 -241
  168. django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +0 -30
  169. django_cfg/apps/payments/models/events.py +0 -73
  170. django_cfg/apps/payments/serializers/__init__.py +0 -57
  171. django_cfg/apps/payments/serializers/api_keys.py +0 -51
  172. django_cfg/apps/payments/serializers/balance.py +0 -59
  173. django_cfg/apps/payments/serializers/currencies.py +0 -63
  174. django_cfg/apps/payments/serializers/payments.py +0 -62
  175. django_cfg/apps/payments/serializers/subscriptions.py +0 -71
  176. django_cfg/apps/payments/serializers/tariffs.py +0 -56
  177. django_cfg/apps/payments/services/billing/__init__.py +0 -8
  178. django_cfg/apps/payments/services/cache/base.py +0 -30
  179. django_cfg/apps/payments/services/core/fallback_service.py +0 -432
  180. django_cfg/apps/payments/services/internal_types.py +0 -461
  181. django_cfg/apps/payments/services/middleware/__init__.py +0 -8
  182. django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
  183. django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -76
  184. django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
  185. django_cfg/apps/payments/services/providers/cryptapi/__init__.py +0 -4
  186. django_cfg/apps/payments/services/providers/cryptapi/config.py +0 -8
  187. django_cfg/apps/payments/services/providers/cryptapi/models.py +0 -192
  188. django_cfg/apps/payments/services/providers/cryptapi/provider.py +0 -439
  189. django_cfg/apps/payments/services/providers/cryptomus/__init__.py +0 -4
  190. django_cfg/apps/payments/services/providers/cryptomus/models.py +0 -176
  191. django_cfg/apps/payments/services/providers/cryptomus/provider.py +0 -429
  192. django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +0 -564
  193. django_cfg/apps/payments/services/providers/models/__init__.py +0 -34
  194. django_cfg/apps/payments/services/providers/models/currencies.py +0 -190
  195. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +0 -4
  196. django_cfg/apps/payments/services/providers/nowpayments/models.py +0 -196
  197. django_cfg/apps/payments/services/providers/nowpayments/provider.py +0 -380
  198. django_cfg/apps/payments/services/providers/stripe/__init__.py +0 -4
  199. django_cfg/apps/payments/services/providers/stripe/models.py +0 -184
  200. django_cfg/apps/payments/services/providers/stripe/provider.py +0 -109
  201. django_cfg/apps/payments/services/security/__init__.py +0 -34
  202. django_cfg/apps/payments/services/security/error_handler.py +0 -635
  203. django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
  204. django_cfg/apps/payments/services/security/webhook_validator.py +0 -474
  205. django_cfg/apps/payments/static/payments/css/payments.css +0 -340
  206. django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
  207. django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
  208. django_cfg/apps/payments/static/payments/js/theme.js +0 -86
  209. django_cfg/apps/payments/tasks/__init__.py +0 -12
  210. django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
  211. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +0 -50
  212. django_cfg/apps/payments/templates/payments/base.html +0 -182
  213. django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
  214. django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
  215. django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -43
  216. django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
  217. django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -34
  218. django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -148
  219. django_cfg/apps/payments/templates/payments/dashboard.html +0 -258
  220. django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +0 -35
  221. django_cfg/apps/payments/templates/payments/payment_create.html +0 -579
  222. django_cfg/apps/payments/templates/payments/payment_detail.html +0 -373
  223. django_cfg/apps/payments/templates/payments/payment_list.html +0 -354
  224. django_cfg/apps/payments/templates/payments/stats.html +0 -261
  225. django_cfg/apps/payments/templates/payments/test.html +0 -213
  226. django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
  227. django_cfg/apps/payments/utils/__init__.py +0 -43
  228. django_cfg/apps/payments/utils/billing_utils.py +0 -342
  229. django_cfg/apps/payments/utils/config_utils.py +0 -239
  230. django_cfg/apps/payments/utils/middleware_utils.py +0 -228
  231. django_cfg/apps/payments/utils/validation_utils.py +0 -94
  232. django_cfg/apps/payments/views/__init__.py +0 -63
  233. django_cfg/apps/payments/views/api_key_views.py +0 -164
  234. django_cfg/apps/payments/views/balance_views.py +0 -75
  235. django_cfg/apps/payments/views/currency_views.py +0 -122
  236. django_cfg/apps/payments/views/payment_views.py +0 -149
  237. django_cfg/apps/payments/views/subscription_views.py +0 -135
  238. django_cfg/apps/payments/views/tariff_views.py +0 -131
  239. django_cfg/apps/payments/views/templates/__init__.py +0 -25
  240. django_cfg/apps/payments/views/templates/ajax.py +0 -451
  241. django_cfg/apps/payments/views/templates/base.py +0 -212
  242. django_cfg/apps/payments/views/templates/dashboard.py +0 -60
  243. django_cfg/apps/payments/views/templates/payment_detail.py +0 -102
  244. django_cfg/apps/payments/views/templates/payment_management.py +0 -158
  245. django_cfg/apps/payments/views/templates/qr_code.py +0 -174
  246. django_cfg/apps/payments/views/templates/stats.py +0 -244
  247. django_cfg/apps/payments/views/templates/utils.py +0 -181
  248. django_cfg/apps/payments/views/webhook_views.py +0 -266
  249. django_cfg/apps/payments/viewsets.py +0 -66
  250. django_cfg/core/integration.py +0 -160
  251. django_cfg/template_archive/.gitignore +0 -1
  252. django_cfg/template_archive/__init__.py +0 -0
  253. django_cfg/urls.py +0 -33
  254. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
  255. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
  256. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,304 +0,0 @@
1
- """
2
- Management command to show currency database statistics.
3
-
4
- Usage:
5
- python manage.py currency_stats
6
- python manage.py currency_stats --detailed
7
- python manage.py currency_stats --top 10
8
- python manage.py currency_stats --check-rates
9
- """
10
-
11
- from datetime import datetime, timedelta
12
- from typing import List
13
-
14
- from django.core.management.base import BaseCommand
15
- from django.utils import timezone
16
- from django.db.models import Q, Count, Avg
17
-
18
- from django_cfg.apps.payments.models.currencies import Currency
19
-
20
-
21
- class Command(BaseCommand):
22
- """
23
- Display currency database statistics and health information.
24
- """
25
-
26
- help = 'Show currency database statistics'
27
-
28
- def add_arguments(self, parser):
29
- """Add command line arguments."""
30
- parser.add_argument(
31
- '--detailed',
32
- action='store_true',
33
- help='Show detailed statistics'
34
- )
35
-
36
- parser.add_argument(
37
- '--top',
38
- type=int,
39
- default=5,
40
- help='Number of top currencies to show (default: 5)'
41
- )
42
-
43
- parser.add_argument(
44
- '--check-rates',
45
- action='store_true',
46
- help='Check for outdated exchange rates'
47
- )
48
-
49
- parser.add_argument(
50
- '--export-csv',
51
- type=str,
52
- help='Export currency data to CSV file'
53
- )
54
-
55
- def handle(self, *args, **options):
56
- """Main command handler."""
57
-
58
- self.stdout.write(
59
- self.style.SUCCESS('📊 Currency Database Statistics')
60
- )
61
- self.stdout.write('=' * 50)
62
-
63
- self._show_basic_stats(options)
64
-
65
- if options['detailed']:
66
- self._show_detailed_stats(options)
67
-
68
- if options['check_rates']:
69
- self._check_rate_freshness()
70
-
71
- if options['export_csv']:
72
- self._export_to_csv(options['export_csv'])
73
-
74
- def _show_basic_stats(self, options):
75
- """Show basic currency statistics."""
76
-
77
- # Basic counts
78
- total = Currency.objects.count()
79
- active = Currency.objects.count()
80
- inactive = total - active
81
-
82
- fiat_count = Currency.objects.filter(currency_type=Currency.CurrencyType.FIAT).count()
83
- crypto_count = Currency.objects.filter(currency_type=Currency.CurrencyType.CRYPTO).count()
84
-
85
- active_fiat = Currency.objects.filter(
86
- currency_type=Currency.CurrencyType.FIAT,
87
- ).count()
88
- active_crypto = Currency.objects.filter(
89
- currency_type=Currency.CurrencyType.CRYPTO,
90
- ).count()
91
-
92
- self.stdout.write(f"\n📈 Overview:")
93
- self.stdout.write(f" Total currencies: {total}")
94
- self.stdout.write(f" Active: {active} | Inactive: {inactive}")
95
- self.stdout.write(f" Fiat: {fiat_count} ({active_fiat} active)")
96
- self.stdout.write(f" Crypto: {crypto_count} ({active_crypto} active)")
97
-
98
- # Rate update status
99
- now = timezone.now()
100
-
101
- # Recent (last 24h)
102
- recent_threshold = now - timedelta(hours=24)
103
- recent_updates = Currency.objects.filter(
104
- rate_updated_at__gte=recent_threshold
105
- ).count()
106
-
107
- # Outdated (older than 7 days)
108
- outdated_threshold = now - timedelta(days=7)
109
- outdated = Currency.objects.filter(
110
- Q(rate_updated_at__lt=outdated_threshold) | Q(rate_updated_at__isnull=True)
111
- ).count()
112
-
113
- self.stdout.write(f"\n🕒 Rate Updates:")
114
- self.stdout.write(f" Updated in last 24h: {recent_updates}")
115
- self.stdout.write(f" Outdated (>7 days): {outdated}")
116
-
117
- # Top cryptocurrencies by USD value
118
- top_crypto = Currency.objects.filter(
119
- currency_type=Currency.CurrencyType.CRYPTO,
120
- ).order_by('-usd_rate')[:options['top']]
121
-
122
- if top_crypto:
123
- self.stdout.write(f"\n🚀 Top {options['top']} Cryptocurrencies by USD Rate:")
124
- for i, currency in enumerate(top_crypto, 1):
125
- age = self._get_rate_age(currency)
126
- self.stdout.write(
127
- f" {i}. {currency.code}: ${currency.usd_rate:,.6f} {age}"
128
- )
129
-
130
- # Major fiat currencies
131
- major_fiat = Currency.objects.filter(
132
- currency_type=Currency.CurrencyType.FIAT,
133
- code__in=['USD', 'EUR', 'GBP', 'JPY', 'CNY'],
134
- ).order_by('code')
135
-
136
- if major_fiat:
137
- self.stdout.write(f"\n💵 Major Fiat Currencies:")
138
- for currency in major_fiat:
139
- age = self._get_rate_age(currency)
140
- self.stdout.write(
141
- f" • {currency.code}: {currency.name} = ${currency.usd_rate:.6f} {age}"
142
- )
143
-
144
- def _show_detailed_stats(self, options):
145
- """Show detailed statistics."""
146
-
147
- self.stdout.write(f"\n📊 Detailed Statistics:")
148
-
149
- # Decimal places distribution
150
- decimal_stats = Currency.objects.values('decimal_places').annotate(
151
- count=Count('decimal_places')
152
- ).order_by('decimal_places')
153
-
154
- self.stdout.write(f"\n🔢 Decimal Places Distribution:")
155
- for stat in decimal_stats:
156
- self.stdout.write(f" {stat['decimal_places']} places: {stat['count']} currencies")
157
-
158
- # Average rates by type
159
- crypto_avg = Currency.objects.filter(
160
- currency_type=Currency.CurrencyType.CRYPTO,
161
- ).aggregate(avg_rate=Avg('usd_rate'))['avg_rate']
162
-
163
- fiat_avg = Currency.objects.filter(
164
- currency_type=Currency.CurrencyType.FIAT,
165
- ).aggregate(avg_rate=Avg('usd_rate'))['avg_rate']
166
-
167
- self.stdout.write(f"\n📊 Average USD Rates:")
168
- if crypto_avg:
169
- self.stdout.write(f" Cryptocurrencies: ${crypto_avg:.6f}")
170
- if fiat_avg:
171
- self.stdout.write(f" Fiat currencies: ${fiat_avg:.6f}")
172
-
173
- # Min payment amounts
174
- # Note: min_payment_amount field was removed - now handled at provider level
175
- self.stdout.write(f"\n💰 Payment amounts now managed at provider level (ProviderCurrency)")
176
-
177
- # Rate freshness distribution
178
- now = timezone.now()
179
- thresholds = [
180
- ('Last hour', timedelta(hours=1)),
181
- ('Last 24 hours', timedelta(hours=24)),
182
- ('Last week', timedelta(days=7)),
183
- ('Last month', timedelta(days=30)),
184
- ]
185
-
186
- self.stdout.write(f"\n⏰ Rate Update Distribution:")
187
- previous_count = 0
188
- for label, delta in thresholds:
189
- threshold = now - delta
190
- count = Currency.objects.filter(rate_updated_at__gte=threshold).count()
191
- new_in_period = count - previous_count
192
- self.stdout.write(f" {label}: {new_in_period} new updates ({count} total)")
193
- previous_count = count
194
-
195
- # Never updated
196
- never_updated = Currency.objects.filter(rate_updated_at__isnull=True).count()
197
- if never_updated > 0:
198
- self.stdout.write(f" Never updated: {never_updated} currencies")
199
-
200
- def _check_rate_freshness(self):
201
- """Check for outdated exchange rates."""
202
-
203
- self.stdout.write(f"\n🔍 Rate Freshness Check:")
204
-
205
- now = timezone.now()
206
-
207
- # Very outdated (>30 days)
208
- very_old_threshold = now - timedelta(days=30)
209
- very_old = Currency.objects.filter(
210
- Q(rate_updated_at__lt=very_old_threshold) | Q(rate_updated_at__isnull=True),
211
- )
212
-
213
- if very_old.exists():
214
- self.stdout.write(
215
- self.style.ERROR(f" ❌ {very_old.count()} currencies with very old rates (>30 days)")
216
- )
217
- for currency in very_old[:5]:
218
- age = self._get_rate_age(currency)
219
- self.stdout.write(f" • {currency.code}: {age}")
220
- if very_old.count() > 5:
221
- self.stdout.write(f" ... and {very_old.count() - 5} more")
222
-
223
- # Moderately outdated (7-30 days)
224
- old_threshold = now - timedelta(days=7)
225
- old_currencies = Currency.objects.filter(
226
- rate_updated_at__lt=old_threshold,
227
- rate_updated_at__gte=very_old_threshold,
228
- )
229
-
230
- if old_currencies.exists():
231
- self.stdout.write(
232
- self.style.WARNING(f" ⚠️ {old_currencies.count()} currencies with old rates (7-30 days)")
233
- )
234
-
235
- # Fresh rates (last 24h)
236
- fresh_threshold = now - timedelta(hours=24)
237
- fresh = Currency.objects.filter(
238
- rate_updated_at__gte=fresh_threshold,
239
- ).count()
240
-
241
- if fresh > 0:
242
- self.stdout.write(
243
- self.style.SUCCESS(f" ✅ {fresh} currencies with fresh rates (<24h)")
244
- )
245
-
246
- # Recommendations
247
- total_active = Currency.objects.count()
248
- if very_old.count() > 0:
249
- self.stdout.write(f"\n💡 Recommendations:")
250
- self.stdout.write(f" • Run: python manage.py update_currencies --force-update")
251
- self.stdout.write(f" • Consider deactivating currencies with very old rates")
252
-
253
- def _get_rate_age(self, currency) -> str:
254
- """Get human-readable age of currency rate."""
255
- if not currency.rate_updated_at:
256
- return "(never updated)"
257
-
258
- age = timezone.now() - currency.rate_updated_at
259
-
260
- if age.days > 30:
261
- return f"({age.days} days ago)"
262
- elif age.days > 0:
263
- return f"({age.days}d ago)"
264
- elif age.seconds > 3600:
265
- hours = age.seconds // 3600
266
- return f"({hours}h ago)"
267
- else:
268
- minutes = age.seconds // 60
269
- return f"({minutes}m ago)"
270
-
271
- def _export_to_csv(self, filename: str):
272
- """Export currency data to CSV file."""
273
- import csv
274
-
275
- self.stdout.write(f"\n📁 Exporting to {filename}...")
276
-
277
- try:
278
- with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
279
- writer = csv.writer(csvfile)
280
-
281
- # Header
282
- writer.writerow([
283
- 'code', 'name', 'currency_type', 'usd_rate', 'rate_updated_at'
284
- ])
285
-
286
- # Data
287
- currencies = Currency.objects.all().order_by('code')
288
- for currency in currencies:
289
- writer.writerow([
290
- currency.code,
291
- currency.name,
292
- currency.currency_type,
293
- currency.usd_rate,
294
- currency.rate_updated_at.isoformat() if currency.rate_updated_at else None
295
- ])
296
-
297
- self.stdout.write(
298
- self.style.SUCCESS(f" ✅ Exported {currencies.count()} currencies to {filename}")
299
- )
300
-
301
- except Exception as e:
302
- self.stdout.write(
303
- self.style.ERROR(f" ❌ Export failed: {str(e)}")
304
- )
@@ -1,23 +0,0 @@
1
- """
2
- Django model managers for universal payments.
3
- """
4
-
5
- from .payment_manager import UniversalPaymentManager
6
- from .balance_manager import UserBalanceManager
7
- from .subscription_manager import SubscriptionManager, EndpointGroupManager
8
- from .tariff_manager import TariffManager, TariffEndpointGroupManager
9
- from .api_key_manager import APIKeyManager
10
- from .currency_manager import CurrencyManager, NetworkManager, ProviderCurrencyManager
11
-
12
- __all__ = [
13
- 'UniversalPaymentManager',
14
- 'UserBalanceManager',
15
- 'SubscriptionManager',
16
- 'EndpointGroupManager',
17
- 'TariffManager',
18
- 'TariffEndpointGroupManager',
19
- 'APIKeyManager',
20
- 'CurrencyManager',
21
- 'NetworkManager',
22
- 'ProviderCurrencyManager',
23
- ]
@@ -1,35 +0,0 @@
1
- """
2
- API key managers.
3
- """
4
-
5
- from django.db import models
6
- from django.utils import timezone
7
-
8
-
9
- class APIKeyManager(models.Manager):
10
- """Manager for APIKey model."""
11
-
12
- def get_active_keys(self, user=None):
13
- """Get active API keys."""
14
- queryset = self.filter(is_active=True)
15
- if user:
16
- queryset = queryset.filter(user=user)
17
- return queryset
18
-
19
- def get_expired_keys(self):
20
- """Get expired API keys."""
21
- return self.filter(
22
- expires_at__lte=timezone.now()
23
- )
24
-
25
- def get_valid_keys(self, user=None):
26
- """Get valid (active and not expired) API keys."""
27
- now = timezone.now()
28
- queryset = self.filter(
29
- is_active=True
30
- ).filter(
31
- models.Q(expires_at__isnull=True) | models.Q(expires_at__gt=now)
32
- )
33
- if user:
34
- queryset = queryset.filter(user=user)
35
- return queryset