django-cfg 1.2.29__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 (258) 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 -9
  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 +600 -108
  9. django_cfg/apps/payments/admin/filters.py +306 -199
  10. django_cfg/apps/payments/admin/payments_admin.py +470 -64
  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 +381 -0
  39. django_cfg/apps/payments/management/commands/manage_providers.py +408 -0
  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 +343 -163
  43. django_cfg/apps/payments/middleware/usage_tracking.py +250 -238
  44. django_cfg/apps/payments/migrations/0001_initial.py +708 -536
  45. django_cfg/apps/payments/models/__init__.py +16 -20
  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 +207 -67
  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 -284
  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 +344 -468
  67. django_cfg/apps/payments/services/core/subscription_service.py +425 -484
  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 +232 -71
  74. django_cfg/apps/payments/services/providers/nowpayments.py +404 -219
  75. django_cfg/apps/payments/services/providers/registry.py +429 -80
  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 +211 -130
  83. django_cfg/apps/payments/signals/balance_signals.py +174 -0
  84. django_cfg/apps/payments/signals/payment_signals.py +129 -98
  85. django_cfg/apps/payments/signals/subscription_signals.py +195 -143
  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 +46 -47
  93. django_cfg/apps/payments/urls_admin.py +49 -0
  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/apps/tasks/urls.py +0 -2
  110. django_cfg/apps/tasks/urls_admin.py +14 -0
  111. django_cfg/apps/urls.py +4 -4
  112. django_cfg/config.py +1 -1
  113. django_cfg/core/config.py +75 -4
  114. django_cfg/core/generation.py +25 -4
  115. django_cfg/core/integration/README.md +363 -0
  116. django_cfg/core/integration/__init__.py +47 -0
  117. django_cfg/core/integration/commands_collector.py +239 -0
  118. django_cfg/core/integration/display/__init__.py +15 -0
  119. django_cfg/core/integration/display/base.py +157 -0
  120. django_cfg/core/integration/display/ngrok.py +164 -0
  121. django_cfg/core/integration/display/startup.py +815 -0
  122. django_cfg/core/integration/url_integration.py +123 -0
  123. django_cfg/core/integration/version_checker.py +160 -0
  124. django_cfg/management/commands/auto_generate.py +4 -0
  125. django_cfg/management/commands/check_settings.py +6 -0
  126. django_cfg/management/commands/clear_constance.py +5 -2
  127. django_cfg/management/commands/create_token.py +6 -0
  128. django_cfg/management/commands/list_urls.py +6 -0
  129. django_cfg/management/commands/migrate_all.py +6 -0
  130. django_cfg/management/commands/migrator.py +3 -0
  131. django_cfg/management/commands/rundramatiq.py +6 -0
  132. django_cfg/management/commands/runserver_ngrok.py +51 -29
  133. django_cfg/management/commands/script.py +6 -0
  134. django_cfg/management/commands/show_config.py +12 -2
  135. django_cfg/management/commands/show_urls.py +4 -0
  136. django_cfg/management/commands/superuser.py +6 -0
  137. django_cfg/management/commands/task_clear.py +4 -1
  138. django_cfg/management/commands/task_status.py +3 -1
  139. django_cfg/management/commands/test_email.py +3 -0
  140. django_cfg/management/commands/test_telegram.py +6 -0
  141. django_cfg/management/commands/test_twilio.py +6 -0
  142. django_cfg/management/commands/tree.py +6 -0
  143. django_cfg/management/commands/validate_config.py +155 -149
  144. django_cfg/models/constance.py +31 -11
  145. django_cfg/models/payments.py +175 -498
  146. django_cfg/modules/django_currency/__init__.py +16 -11
  147. django_cfg/modules/django_currency/clients/__init__.py +4 -4
  148. django_cfg/modules/django_currency/clients/coinpaprika_client.py +289 -0
  149. django_cfg/modules/django_currency/clients/yahoo_client.py +157 -0
  150. django_cfg/modules/django_currency/core/__init__.py +1 -7
  151. django_cfg/modules/django_currency/core/converter.py +18 -23
  152. django_cfg/modules/django_currency/core/models.py +122 -11
  153. django_cfg/modules/django_currency/database/__init__.py +4 -4
  154. django_cfg/modules/django_currency/database/database_loader.py +190 -309
  155. django_cfg/modules/django_logger.py +160 -146
  156. django_cfg/modules/django_unfold/dashboard.py +65 -12
  157. django_cfg/registry/core.py +1 -0
  158. django_cfg/template_archive/django_sample.zip +0 -0
  159. django_cfg/templates/admin/components/action_grid.html +9 -9
  160. django_cfg/templates/admin/components/metric_card.html +5 -5
  161. django_cfg/templates/admin/components/status_badge.html +2 -2
  162. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +152 -24
  163. django_cfg/templates/admin/snippets/components/quick_actions.html +3 -3
  164. django_cfg/templates/admin/snippets/components/system_health.html +1 -1
  165. django_cfg/templates/admin/snippets/tabs/overview_tab.html +49 -52
  166. django_cfg/utils/smart_defaults.py +222 -571
  167. django_cfg/utils/toolkit.py +51 -11
  168. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/METADATA +5 -4
  169. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/RECORD +172 -182
  170. django_cfg/apps/payments/__init__.py +0 -8
  171. django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
  172. django_cfg/apps/payments/config/module.py +0 -70
  173. django_cfg/apps/payments/config/providers.py +0 -105
  174. django_cfg/apps/payments/config/settings.py +0 -96
  175. django_cfg/apps/payments/config/utils.py +0 -52
  176. django_cfg/apps/payments/decorators.py +0 -291
  177. django_cfg/apps/payments/management/commands/README.md +0 -178
  178. django_cfg/apps/payments/management/commands/currency_stats.py +0 -323
  179. django_cfg/apps/payments/management/commands/populate_currencies.py +0 -246
  180. django_cfg/apps/payments/management/commands/update_currencies.py +0 -336
  181. django_cfg/apps/payments/managers/__init__.py +0 -22
  182. django_cfg/apps/payments/managers/api_key_manager.py +0 -35
  183. django_cfg/apps/payments/managers/balance_manager.py +0 -361
  184. django_cfg/apps/payments/managers/currency_manager.py +0 -83
  185. django_cfg/apps/payments/managers/payment_manager.py +0 -44
  186. django_cfg/apps/payments/managers/subscription_manager.py +0 -37
  187. django_cfg/apps/payments/managers/tariff_manager.py +0 -29
  188. django_cfg/apps/payments/models/events.py +0 -73
  189. django_cfg/apps/payments/serializers/__init__.py +0 -56
  190. django_cfg/apps/payments/serializers/api_keys.py +0 -51
  191. django_cfg/apps/payments/serializers/balance.py +0 -59
  192. django_cfg/apps/payments/serializers/currencies.py +0 -55
  193. django_cfg/apps/payments/serializers/payments.py +0 -62
  194. django_cfg/apps/payments/serializers/subscriptions.py +0 -71
  195. django_cfg/apps/payments/serializers/tariffs.py +0 -56
  196. django_cfg/apps/payments/services/billing/__init__.py +0 -8
  197. django_cfg/apps/payments/services/cache/base.py +0 -30
  198. django_cfg/apps/payments/services/core/fallback_service.py +0 -432
  199. django_cfg/apps/payments/services/internal_types.py +0 -297
  200. django_cfg/apps/payments/services/middleware/__init__.py +0 -8
  201. django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
  202. django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -222
  203. django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
  204. django_cfg/apps/payments/services/providers/cryptapi.py +0 -273
  205. django_cfg/apps/payments/services/providers/cryptomus.py +0 -311
  206. django_cfg/apps/payments/services/security/__init__.py +0 -34
  207. django_cfg/apps/payments/services/security/error_handler.py +0 -637
  208. django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
  209. django_cfg/apps/payments/services/security/webhook_validator.py +0 -475
  210. django_cfg/apps/payments/services/validators/__init__.py +0 -8
  211. django_cfg/apps/payments/static/payments/css/payments.css +0 -340
  212. django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
  213. django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
  214. django_cfg/apps/payments/static/payments/js/theme.js +0 -86
  215. django_cfg/apps/payments/tasks/__init__.py +0 -12
  216. django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
  217. django_cfg/apps/payments/templates/payments/base.html +0 -182
  218. django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
  219. django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
  220. django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -36
  221. django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
  222. django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -27
  223. django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -144
  224. django_cfg/apps/payments/templates/payments/dashboard.html +0 -346
  225. django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
  226. django_cfg/apps/payments/urls_templates.py +0 -52
  227. django_cfg/apps/payments/utils/__init__.py +0 -45
  228. django_cfg/apps/payments/utils/billing_utils.py +0 -342
  229. django_cfg/apps/payments/utils/config_utils.py +0 -245
  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 -62
  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 -111
  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 -312
  241. django_cfg/apps/payments/views/templates/base.py +0 -204
  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 -164
  245. django_cfg/apps/payments/views/templates/qr_code.py +0 -174
  246. django_cfg/apps/payments/views/templates/stats.py +0 -240
  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 -65
  250. django_cfg/core/integration.py +0 -160
  251. django_cfg/modules/django_currency/clients/coingecko_client.py +0 -257
  252. django_cfg/modules/django_currency/clients/yfinance_client.py +0 -246
  253. django_cfg/template_archive/.gitignore +0 -1
  254. django_cfg/template_archive/__init__.py +0 -0
  255. django_cfg/urls.py +0 -33
  256. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
  257. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
  258. {django_cfg-1.2.29.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