django-cfg 1.2.31__py3-none-any.whl → 1.3.3__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 (264) 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/cleanup_expired_data.py +419 -0
  39. django_cfg/apps/payments/management/commands/currency_stats.py +297 -225
  40. django_cfg/apps/payments/management/commands/manage_currencies.py +303 -151
  41. django_cfg/apps/payments/management/commands/manage_providers.py +333 -160
  42. django_cfg/apps/payments/management/commands/process_pending_payments.py +357 -0
  43. django_cfg/apps/payments/management/commands/test_providers.py +434 -0
  44. django_cfg/apps/payments/middleware/__init__.py +3 -1
  45. django_cfg/apps/payments/middleware/api_access.py +329 -222
  46. django_cfg/apps/payments/middleware/rate_limiting.py +342 -152
  47. django_cfg/apps/payments/middleware/usage_tracking.py +249 -240
  48. django_cfg/apps/payments/migrations/0001_initial.py +708 -536
  49. django_cfg/apps/payments/models/__init__.py +13 -18
  50. django_cfg/apps/payments/models/api_keys.py +121 -43
  51. django_cfg/apps/payments/models/balance.py +153 -115
  52. django_cfg/apps/payments/models/base.py +68 -15
  53. django_cfg/apps/payments/models/currencies.py +172 -148
  54. django_cfg/apps/payments/models/managers/__init__.py +44 -0
  55. django_cfg/apps/payments/models/managers/api_key_managers.py +329 -0
  56. django_cfg/apps/payments/models/managers/balance_managers.py +599 -0
  57. django_cfg/apps/payments/models/managers/currency_managers.py +385 -0
  58. django_cfg/apps/payments/models/managers/payment_managers.py +511 -0
  59. django_cfg/apps/payments/models/managers/subscription_managers.py +641 -0
  60. django_cfg/apps/payments/models/payments.py +235 -285
  61. django_cfg/apps/payments/models/subscriptions.py +257 -177
  62. django_cfg/apps/payments/models/tariffs.py +147 -40
  63. django_cfg/apps/payments/services/__init__.py +209 -56
  64. django_cfg/apps/payments/services/cache/__init__.py +6 -6
  65. django_cfg/apps/payments/services/cache_service/__init__.py +143 -0
  66. django_cfg/apps/payments/services/cache_service/api_key_cache.py +37 -0
  67. django_cfg/apps/payments/services/{cache/base.py → cache_service/interfaces.py} +3 -1
  68. django_cfg/apps/payments/services/cache_service/keys.py +49 -0
  69. django_cfg/apps/payments/services/cache_service/rate_limit_cache.py +47 -0
  70. django_cfg/apps/payments/services/cache_service/simple_cache.py +101 -0
  71. django_cfg/apps/payments/services/core/__init__.py +10 -6
  72. django_cfg/apps/payments/services/core/balance_service.py +435 -360
  73. django_cfg/apps/payments/services/core/base.py +166 -0
  74. django_cfg/apps/payments/services/core/currency_service.py +478 -0
  75. django_cfg/apps/payments/services/core/payment_service.py +371 -465
  76. django_cfg/apps/payments/services/core/subscription_service.py +425 -481
  77. django_cfg/apps/payments/services/core/webhook_service.py +410 -0
  78. django_cfg/apps/payments/services/integrations/__init__.py +29 -0
  79. django_cfg/apps/payments/services/integrations/ngrok_service.py +47 -0
  80. django_cfg/apps/payments/services/integrations/providers_config.py +107 -0
  81. django_cfg/apps/payments/services/providers/__init__.py +9 -14
  82. django_cfg/apps/payments/services/providers/base.py +234 -174
  83. django_cfg/apps/payments/services/providers/nowpayments.py +478 -0
  84. django_cfg/apps/payments/services/providers/registry.py +367 -301
  85. django_cfg/apps/payments/services/types/__init__.py +78 -0
  86. django_cfg/apps/payments/services/types/data.py +177 -0
  87. django_cfg/apps/payments/services/types/requests.py +150 -0
  88. django_cfg/apps/payments/services/types/responses.py +156 -0
  89. django_cfg/apps/payments/services/types/webhooks.py +232 -0
  90. django_cfg/apps/payments/signals/__init__.py +33 -8
  91. django_cfg/apps/payments/signals/api_key_signals.py +210 -129
  92. django_cfg/apps/payments/signals/balance_signals.py +174 -0
  93. django_cfg/apps/payments/signals/payment_signals.py +128 -103
  94. django_cfg/apps/payments/signals/subscription_signals.py +194 -142
  95. django_cfg/apps/payments/static/payments/css/components.css +380 -0
  96. django_cfg/apps/payments/static/payments/css/dashboard.css +188 -0
  97. django_cfg/apps/payments/static/payments/js/components.js +545 -0
  98. django_cfg/apps/payments/static/payments/js/utils.js +412 -0
  99. django_cfg/apps/payments/templatetags/__init__.py +1 -1
  100. django_cfg/apps/payments/templatetags/payment_tags.py +466 -0
  101. django_cfg/apps/payments/urls.py +45 -48
  102. django_cfg/apps/payments/urls_admin.py +33 -42
  103. django_cfg/apps/payments/views/api/__init__.py +101 -0
  104. django_cfg/apps/payments/views/api/api_keys.py +387 -0
  105. django_cfg/apps/payments/views/api/balances.py +381 -0
  106. django_cfg/apps/payments/views/api/base.py +298 -0
  107. django_cfg/apps/payments/views/api/currencies.py +402 -0
  108. django_cfg/apps/payments/views/api/payments.py +415 -0
  109. django_cfg/apps/payments/views/api/subscriptions.py +475 -0
  110. django_cfg/apps/payments/views/api/webhooks.py +476 -0
  111. django_cfg/apps/payments/views/serializers/__init__.py +99 -0
  112. django_cfg/apps/payments/views/serializers/api_keys.py +424 -0
  113. django_cfg/apps/payments/views/serializers/balances.py +300 -0
  114. django_cfg/apps/payments/views/serializers/currencies.py +335 -0
  115. django_cfg/apps/payments/views/serializers/payments.py +387 -0
  116. django_cfg/apps/payments/views/serializers/subscriptions.py +429 -0
  117. django_cfg/apps/payments/views/serializers/webhooks.py +137 -0
  118. django_cfg/config.py +1 -1
  119. django_cfg/core/config.py +40 -4
  120. django_cfg/core/generation.py +25 -4
  121. django_cfg/core/integration/README.md +363 -0
  122. django_cfg/core/integration/__init__.py +47 -0
  123. django_cfg/core/integration/commands_collector.py +239 -0
  124. django_cfg/core/integration/display/__init__.py +15 -0
  125. django_cfg/core/integration/display/base.py +157 -0
  126. django_cfg/core/integration/display/ngrok.py +164 -0
  127. django_cfg/core/integration/display/startup.py +815 -0
  128. django_cfg/core/integration/url_integration.py +123 -0
  129. django_cfg/core/integration/version_checker.py +160 -0
  130. django_cfg/management/commands/auto_generate.py +4 -0
  131. django_cfg/management/commands/check_settings.py +6 -0
  132. django_cfg/management/commands/clear_constance.py +5 -2
  133. django_cfg/management/commands/create_token.py +6 -0
  134. django_cfg/management/commands/list_urls.py +6 -0
  135. django_cfg/management/commands/migrate_all.py +6 -0
  136. django_cfg/management/commands/migrator.py +3 -0
  137. django_cfg/management/commands/rundramatiq.py +6 -0
  138. django_cfg/management/commands/runserver_ngrok.py +51 -29
  139. django_cfg/management/commands/script.py +6 -0
  140. django_cfg/management/commands/show_config.py +12 -2
  141. django_cfg/management/commands/show_urls.py +4 -0
  142. django_cfg/management/commands/superuser.py +6 -0
  143. django_cfg/management/commands/task_clear.py +4 -1
  144. django_cfg/management/commands/task_status.py +3 -1
  145. django_cfg/management/commands/test_email.py +3 -0
  146. django_cfg/management/commands/test_telegram.py +6 -0
  147. django_cfg/management/commands/test_twilio.py +6 -0
  148. django_cfg/management/commands/tree.py +6 -0
  149. django_cfg/management/commands/validate_config.py +155 -149
  150. django_cfg/models/constance.py +31 -11
  151. django_cfg/models/payments.py +175 -492
  152. django_cfg/modules/django_logger.py +160 -146
  153. django_cfg/modules/django_unfold/dashboard.py +64 -16
  154. django_cfg/registry/core.py +1 -0
  155. django_cfg/template_archive/django_sample.zip +0 -0
  156. django_cfg/utils/smart_defaults.py +227 -570
  157. django_cfg/utils/toolkit.py +51 -11
  158. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/METADATA +4 -1
  159. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/RECORD +162 -185
  160. django_cfg/apps/payments/__init__.py +0 -8
  161. django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
  162. django_cfg/apps/payments/config/module.py +0 -70
  163. django_cfg/apps/payments/config/providers.py +0 -105
  164. django_cfg/apps/payments/config/settings.py +0 -96
  165. django_cfg/apps/payments/config/utils.py +0 -52
  166. django_cfg/apps/payments/decorators.py +0 -291
  167. django_cfg/apps/payments/management/commands/README.md +0 -146
  168. django_cfg/apps/payments/managers/__init__.py +0 -23
  169. django_cfg/apps/payments/managers/api_key_manager.py +0 -35
  170. django_cfg/apps/payments/managers/balance_manager.py +0 -361
  171. django_cfg/apps/payments/managers/currency_manager.py +0 -306
  172. django_cfg/apps/payments/managers/payment_manager.py +0 -192
  173. django_cfg/apps/payments/managers/subscription_manager.py +0 -37
  174. django_cfg/apps/payments/managers/tariff_manager.py +0 -29
  175. django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +0 -241
  176. django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +0 -30
  177. django_cfg/apps/payments/models/events.py +0 -73
  178. django_cfg/apps/payments/serializers/__init__.py +0 -57
  179. django_cfg/apps/payments/serializers/api_keys.py +0 -51
  180. django_cfg/apps/payments/serializers/balance.py +0 -59
  181. django_cfg/apps/payments/serializers/currencies.py +0 -63
  182. django_cfg/apps/payments/serializers/payments.py +0 -62
  183. django_cfg/apps/payments/serializers/subscriptions.py +0 -71
  184. django_cfg/apps/payments/serializers/tariffs.py +0 -56
  185. django_cfg/apps/payments/services/billing/__init__.py +0 -8
  186. django_cfg/apps/payments/services/cache/simple_cache.py +0 -135
  187. django_cfg/apps/payments/services/core/fallback_service.py +0 -432
  188. django_cfg/apps/payments/services/internal_types.py +0 -461
  189. django_cfg/apps/payments/services/middleware/__init__.py +0 -8
  190. django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
  191. django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -76
  192. django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
  193. django_cfg/apps/payments/services/providers/cryptapi/__init__.py +0 -4
  194. django_cfg/apps/payments/services/providers/cryptapi/config.py +0 -8
  195. django_cfg/apps/payments/services/providers/cryptapi/models.py +0 -192
  196. django_cfg/apps/payments/services/providers/cryptapi/provider.py +0 -439
  197. django_cfg/apps/payments/services/providers/cryptomus/__init__.py +0 -4
  198. django_cfg/apps/payments/services/providers/cryptomus/models.py +0 -176
  199. django_cfg/apps/payments/services/providers/cryptomus/provider.py +0 -429
  200. django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +0 -564
  201. django_cfg/apps/payments/services/providers/models/__init__.py +0 -34
  202. django_cfg/apps/payments/services/providers/models/currencies.py +0 -190
  203. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +0 -4
  204. django_cfg/apps/payments/services/providers/nowpayments/models.py +0 -196
  205. django_cfg/apps/payments/services/providers/nowpayments/provider.py +0 -380
  206. django_cfg/apps/payments/services/providers/stripe/__init__.py +0 -4
  207. django_cfg/apps/payments/services/providers/stripe/models.py +0 -184
  208. django_cfg/apps/payments/services/providers/stripe/provider.py +0 -109
  209. django_cfg/apps/payments/services/security/__init__.py +0 -34
  210. django_cfg/apps/payments/services/security/error_handler.py +0 -635
  211. django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
  212. django_cfg/apps/payments/services/security/webhook_validator.py +0 -474
  213. django_cfg/apps/payments/static/payments/css/payments.css +0 -340
  214. django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
  215. django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
  216. django_cfg/apps/payments/static/payments/js/theme.js +0 -86
  217. django_cfg/apps/payments/tasks/__init__.py +0 -12
  218. django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
  219. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +0 -50
  220. django_cfg/apps/payments/templates/payments/base.html +0 -182
  221. django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
  222. django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
  223. django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -43
  224. django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
  225. django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -34
  226. django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -148
  227. django_cfg/apps/payments/templates/payments/dashboard.html +0 -258
  228. django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +0 -35
  229. django_cfg/apps/payments/templates/payments/payment_create.html +0 -579
  230. django_cfg/apps/payments/templates/payments/payment_detail.html +0 -373
  231. django_cfg/apps/payments/templates/payments/payment_list.html +0 -354
  232. django_cfg/apps/payments/templates/payments/stats.html +0 -261
  233. django_cfg/apps/payments/templates/payments/test.html +0 -213
  234. django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
  235. django_cfg/apps/payments/utils/__init__.py +0 -43
  236. django_cfg/apps/payments/utils/billing_utils.py +0 -342
  237. django_cfg/apps/payments/utils/config_utils.py +0 -239
  238. django_cfg/apps/payments/utils/middleware_utils.py +0 -228
  239. django_cfg/apps/payments/utils/validation_utils.py +0 -94
  240. django_cfg/apps/payments/views/__init__.py +0 -63
  241. django_cfg/apps/payments/views/api_key_views.py +0 -164
  242. django_cfg/apps/payments/views/balance_views.py +0 -75
  243. django_cfg/apps/payments/views/currency_views.py +0 -122
  244. django_cfg/apps/payments/views/payment_views.py +0 -149
  245. django_cfg/apps/payments/views/subscription_views.py +0 -135
  246. django_cfg/apps/payments/views/tariff_views.py +0 -131
  247. django_cfg/apps/payments/views/templates/__init__.py +0 -25
  248. django_cfg/apps/payments/views/templates/ajax.py +0 -451
  249. django_cfg/apps/payments/views/templates/base.py +0 -212
  250. django_cfg/apps/payments/views/templates/dashboard.py +0 -60
  251. django_cfg/apps/payments/views/templates/payment_detail.py +0 -102
  252. django_cfg/apps/payments/views/templates/payment_management.py +0 -158
  253. django_cfg/apps/payments/views/templates/qr_code.py +0 -174
  254. django_cfg/apps/payments/views/templates/stats.py +0 -244
  255. django_cfg/apps/payments/views/templates/utils.py +0 -181
  256. django_cfg/apps/payments/views/webhook_views.py +0 -266
  257. django_cfg/apps/payments/viewsets.py +0 -66
  258. django_cfg/core/integration.py +0 -160
  259. django_cfg/template_archive/.gitignore +0 -1
  260. django_cfg/template_archive/__init__.py +0 -0
  261. django_cfg/urls.py +0 -33
  262. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/WHEEL +0 -0
  263. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/entry_points.txt +0 -0
  264. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,385 @@
1
+ """
2
+ Currency managers for the Universal Payment System v2.0.
3
+
4
+ Optimized querysets and managers for currency operations with django_currency integration.
5
+ """
6
+
7
+ from django.db import models
8
+ from django_cfg.modules.django_logger import get_logger
9
+
10
+ logger = get_logger("currency_managers")
11
+
12
+
13
+ class CurrencyQuerySet(models.QuerySet):
14
+ """
15
+ Optimized queryset for currency operations.
16
+
17
+ Provides efficient queries for currency management and conversion.
18
+ """
19
+
20
+ def active(self):
21
+ """Get active currencies."""
22
+ return self.filter(is_active=True)
23
+
24
+ def inactive(self):
25
+ """Get inactive currencies."""
26
+ return self.filter(is_active=False)
27
+
28
+ def by_type(self, currency_type):
29
+ """Filter by currency type (fiat/crypto)."""
30
+ return self.filter(currency_type=currency_type)
31
+
32
+ def crypto(self):
33
+ """Get cryptocurrency currencies."""
34
+ return self.filter(currency_type='crypto')
35
+
36
+ def fiat(self):
37
+ """Get fiat currencies."""
38
+ return self.filter(currency_type='fiat')
39
+
40
+ def by_code(self, code):
41
+ """Filter by currency code."""
42
+ return self.filter(code=code.upper())
43
+
44
+ def supported_by_provider(self, provider):
45
+ """
46
+ Get currencies supported by specific provider.
47
+
48
+ Args:
49
+ provider: Provider name (e.g., 'nowpayments')
50
+ """
51
+ return self.filter(
52
+ provider_configs__provider=provider,
53
+ provider_configs__is_enabled=True,
54
+ is_active=True
55
+ ).distinct()
56
+
57
+ def with_networks(self):
58
+ """Get currencies that have associated networks (crypto only)."""
59
+ return self.crypto().filter(provider_configs__network__isnull=False).distinct()
60
+
61
+ def without_networks(self):
62
+ """Get currencies without networks (typically fiat)."""
63
+ return self.filter(provider_configs__network__isnull=True).distinct()
64
+
65
+ def popular(self):
66
+ """
67
+ Get popular currencies based on usage.
68
+
69
+ This would typically be based on payment volume or frequency.
70
+ For now, returns major currencies.
71
+ """
72
+ popular_codes = ['USD', 'EUR', 'BTC', 'ETH', 'USDT', 'USDC']
73
+ return self.filter(code__in=popular_codes, is_active=True)
74
+
75
+ def search(self, query):
76
+ """
77
+ Search currencies by code or name.
78
+
79
+ Args:
80
+ query: Search query string
81
+ """
82
+ return self.filter(
83
+ models.Q(code__icontains=query) |
84
+ models.Q(name__icontains=query)
85
+ )
86
+
87
+
88
+ class CurrencyManager(models.Manager):
89
+ """
90
+ Manager for currency operations with django_currency integration.
91
+
92
+ Provides high-level methods for currency management and conversion.
93
+ """
94
+
95
+ def get_queryset(self):
96
+ """Return custom queryset."""
97
+ return CurrencyQuerySet(self.model, using=self._db)
98
+
99
+ def active(self):
100
+ """Get active currencies."""
101
+ return self.get_queryset().active()
102
+
103
+ def crypto(self):
104
+ """Get active cryptocurrencies."""
105
+ return self.get_queryset().crypto().active()
106
+
107
+ def fiat(self):
108
+ """Get active fiat currencies."""
109
+ return self.get_queryset().fiat().active()
110
+
111
+ def by_code(self, code):
112
+ """Get currency by code."""
113
+ try:
114
+ return self.get_queryset().by_code(code).get()
115
+ except self.model.DoesNotExist:
116
+ return None
117
+
118
+ def supported_by_provider(self, provider):
119
+ """Get currencies supported by provider."""
120
+ return self.get_queryset().supported_by_provider(provider)
121
+
122
+ def popular(self):
123
+ """Get popular currencies."""
124
+ return self.get_queryset().popular()
125
+
126
+ def get_or_create_currency(self, code, name=None, currency_type=None, **kwargs):
127
+ """
128
+ Get existing currency or create new one.
129
+
130
+ Args:
131
+ code: Currency code (e.g., 'BTC')
132
+ name: Currency name (e.g., 'Bitcoin')
133
+ currency_type: 'crypto' or 'fiat'
134
+ **kwargs: Additional currency fields
135
+
136
+ Returns:
137
+ tuple: (Currency, created)
138
+ """
139
+ code = code.upper()
140
+
141
+ # Try to get existing currency
142
+ try:
143
+ currency = self.get(code=code)
144
+ return currency, False
145
+ except self.model.DoesNotExist:
146
+ pass
147
+
148
+ # Auto-detect currency type if not provided
149
+ if not currency_type:
150
+ # Simple heuristic: common fiat currencies
151
+ fiat_codes = ['USD', 'EUR', 'GBP', 'JPY', 'CAD', 'AUD', 'CHF', 'CNY', 'RUB']
152
+ currency_type = 'fiat' if code in fiat_codes else 'crypto'
153
+
154
+ # Auto-generate name if not provided
155
+ if not name:
156
+ name = self._generate_currency_name(code, currency_type)
157
+
158
+ # Set defaults based on currency type
159
+ defaults = {
160
+ 'name': name,
161
+ 'currency_type': currency_type,
162
+ 'decimal_places': 2 if currency_type == 'fiat' else 8,
163
+ 'is_active': True,
164
+ **kwargs
165
+ }
166
+
167
+ currency = self.create(code=code, **defaults)
168
+
169
+ logger.info(f"Created new currency", extra={
170
+ 'code': code,
171
+ 'name': name,
172
+ 'currency_type': currency_type
173
+ })
174
+
175
+ return currency, True
176
+
177
+ def _generate_currency_name(self, code, currency_type):
178
+ """Generate currency name from code."""
179
+ # Common currency names
180
+ names = {
181
+ # Fiat
182
+ 'USD': 'US Dollar',
183
+ 'EUR': 'Euro',
184
+ 'GBP': 'British Pound',
185
+ 'JPY': 'Japanese Yen',
186
+ 'CAD': 'Canadian Dollar',
187
+ 'AUD': 'Australian Dollar',
188
+ 'CHF': 'Swiss Franc',
189
+ 'CNY': 'Chinese Yuan',
190
+ 'RUB': 'Russian Ruble',
191
+
192
+ # Crypto
193
+ 'BTC': 'Bitcoin',
194
+ 'ETH': 'Ethereum',
195
+ 'LTC': 'Litecoin',
196
+ 'XMR': 'Monero',
197
+ 'USDT': 'Tether',
198
+ 'USDC': 'USD Coin',
199
+ 'ADA': 'Cardano',
200
+ 'DOT': 'Polkadot',
201
+ 'MATIC': 'Polygon',
202
+ 'BNB': 'Binance Coin',
203
+ }
204
+
205
+ return names.get(code, f"{code} {'Cryptocurrency' if currency_type == 'crypto' else 'Currency'}")
206
+
207
+ def sync_with_django_currency(self):
208
+ """
209
+ Sync currencies with django_currency module.
210
+
211
+ This method would integrate with the django_currency module
212
+ to ensure our currency list is up-to-date.
213
+ """
214
+ try:
215
+ from django_cfg.modules.django_currency import get_supported_currencies
216
+
217
+ # Get supported currencies from django_currency
218
+ supported = get_supported_currencies()
219
+
220
+ created_count = 0
221
+ updated_count = 0
222
+
223
+ for currency_info in supported:
224
+ currency, created = self.get_or_create_currency(
225
+ code=currency_info['code'],
226
+ name=currency_info.get('name'),
227
+ currency_type=currency_info.get('type', 'crypto')
228
+ )
229
+
230
+ if created:
231
+ created_count += 1
232
+ else:
233
+ # Update exchange rate source if available
234
+ if currency_info.get('source') and not currency.exchange_rate_source:
235
+ currency.exchange_rate_source = currency_info['source']
236
+ currency.save(update_fields=['exchange_rate_source'])
237
+ updated_count += 1
238
+
239
+ logger.info(f"Synced currencies with django_currency", extra={
240
+ 'created': created_count,
241
+ 'updated': updated_count,
242
+ 'total': len(supported)
243
+ })
244
+
245
+ return {
246
+ 'created': created_count,
247
+ 'updated': updated_count,
248
+ 'total': len(supported)
249
+ }
250
+
251
+ except ImportError:
252
+ logger.warning("django_currency module not available for sync")
253
+ return {'error': 'django_currency module not available'}
254
+ except Exception as e:
255
+ logger.error(f"Failed to sync with django_currency: {e}")
256
+ return {'error': str(e)}
257
+
258
+ def get_conversion_rate(self, from_code, to_code):
259
+ """
260
+ Get conversion rate between currencies using django_currency.
261
+
262
+ Args:
263
+ from_code: Source currency code
264
+ to_code: Target currency code
265
+
266
+ Returns:
267
+ float: Conversion rate or None if unavailable
268
+ """
269
+ try:
270
+ from django_cfg.modules.django_currency import get_exchange_rate
271
+
272
+ rate = get_exchange_rate(from_code.upper(), to_code.upper())
273
+
274
+ logger.debug(f"Retrieved conversion rate", extra={
275
+ 'from_currency': from_code,
276
+ 'to_currency': to_code,
277
+ 'rate': rate
278
+ })
279
+
280
+ return rate
281
+
282
+ except Exception as e:
283
+ logger.error(f"Failed to get conversion rate: {e}", extra={
284
+ 'from_currency': from_code,
285
+ 'to_currency': to_code
286
+ })
287
+ return None
288
+
289
+ def convert_amount(self, amount, from_code, to_code):
290
+ """
291
+ Convert amount between currencies using django_currency.
292
+
293
+ Args:
294
+ amount: Amount to convert
295
+ from_code: Source currency code
296
+ to_code: Target currency code
297
+
298
+ Returns:
299
+ float: Converted amount or None if conversion failed
300
+ """
301
+ try:
302
+ from django_cfg.modules.django_currency import convert_currency
303
+
304
+ converted = convert_currency(amount, from_code.upper(), to_code.upper())
305
+
306
+ logger.debug(f"Converted currency amount", extra={
307
+ 'amount': amount,
308
+ 'from_currency': from_code,
309
+ 'to_currency': to_code,
310
+ 'converted_amount': converted
311
+ })
312
+
313
+ return converted
314
+
315
+ except Exception as e:
316
+ logger.error(f"Failed to convert currency: {e}", extra={
317
+ 'amount': amount,
318
+ 'from_currency': from_code,
319
+ 'to_currency': to_code
320
+ })
321
+ return None
322
+
323
+ def get_supported_currencies_for_provider(self, provider):
324
+ """
325
+ Get list of currencies supported by a specific provider.
326
+
327
+ Args:
328
+ provider: Provider name
329
+
330
+ Returns:
331
+ list: List of currency dictionaries
332
+ """
333
+ currencies = self.supported_by_provider(provider).select_related().prefetch_related(
334
+ 'provider_configs'
335
+ )
336
+
337
+ result = []
338
+ for currency in currencies:
339
+ provider_config = currency.provider_configs.filter(
340
+ provider=provider,
341
+ is_enabled=True
342
+ ).first()
343
+
344
+ if provider_config:
345
+ result.append({
346
+ 'code': currency.code,
347
+ 'name': currency.name,
348
+ 'type': currency.currency_type,
349
+ 'symbol': currency.symbol,
350
+ 'decimal_places': currency.decimal_places,
351
+ 'min_amount': float(provider_config.min_amount) if provider_config.min_amount else None,
352
+ 'max_amount': float(provider_config.max_amount) if provider_config.max_amount else None,
353
+ 'network': provider_config.network.code if provider_config.network else None,
354
+ 'fee_percentage': float(provider_config.fee_percentage),
355
+ 'fixed_fee': float(provider_config.fixed_fee),
356
+ })
357
+
358
+ return result
359
+
360
+ def get_currency_stats(self):
361
+ """
362
+ Get currency statistics.
363
+
364
+ Returns:
365
+ dict: Currency statistics
366
+ """
367
+ queryset = self.get_queryset()
368
+
369
+ stats = {
370
+ 'total_currencies': queryset.count(),
371
+ 'active_currencies': queryset.active().count(),
372
+ 'crypto_currencies': queryset.crypto().count(),
373
+ 'fiat_currencies': queryset.fiat().count(),
374
+ 'with_provider_support': queryset.filter(provider_configs__isnull=False).distinct().count(),
375
+ 'popular_currencies': queryset.popular().count(),
376
+ }
377
+
378
+ # Add provider breakdown
379
+ stats['by_provider'] = {}
380
+ providers = queryset.values_list('provider_configs__provider', flat=True).distinct()
381
+ for provider in providers:
382
+ if provider: # Skip None values
383
+ stats['by_provider'][provider] = queryset.supported_by_provider(provider).count()
384
+
385
+ return stats