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
@@ -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