django-cfg 1.3.7__py3-none-any.whl → 1.3.11__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 (246) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/__init__.py +24 -8
  3. django_cfg/apps/accounts/admin/activity_admin.py +146 -0
  4. django_cfg/apps/accounts/admin/filters.py +98 -22
  5. django_cfg/apps/accounts/admin/group_admin.py +86 -0
  6. django_cfg/apps/accounts/admin/inlines.py +42 -13
  7. django_cfg/apps/accounts/admin/otp_admin.py +115 -0
  8. django_cfg/apps/accounts/admin/registration_admin.py +173 -0
  9. django_cfg/apps/accounts/admin/resources.py +123 -19
  10. django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
  11. django_cfg/apps/accounts/admin/user_admin.py +362 -0
  12. django_cfg/apps/agents/admin/__init__.py +17 -4
  13. django_cfg/apps/agents/admin/execution_admin.py +204 -183
  14. django_cfg/apps/agents/admin/registry_admin.py +230 -255
  15. django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
  16. django_cfg/apps/agents/core/__init__.py +1 -1
  17. django_cfg/apps/agents/core/django_agent.py +221 -0
  18. django_cfg/apps/agents/core/exceptions.py +14 -0
  19. django_cfg/apps/agents/core/orchestrator.py +18 -3
  20. django_cfg/apps/knowbase/admin/__init__.py +1 -1
  21. django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
  22. django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
  23. django_cfg/apps/knowbase/admin/document_admin.py +269 -262
  24. django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
  25. django_cfg/apps/knowbase/config/settings.py +21 -4
  26. django_cfg/apps/knowbase/views/chat_views.py +3 -0
  27. django_cfg/apps/leads/admin/__init__.py +3 -1
  28. django_cfg/apps/leads/admin/leads_admin.py +235 -35
  29. django_cfg/apps/maintenance/admin/__init__.py +2 -2
  30. django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
  31. django_cfg/apps/maintenance/admin/log_admin.py +143 -61
  32. django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
  33. django_cfg/apps/maintenance/admin/site_admin.py +213 -352
  34. django_cfg/apps/newsletter/admin/__init__.py +29 -2
  35. django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
  36. django_cfg/apps/payments/admin/__init__.py +18 -27
  37. django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
  38. django_cfg/apps/payments/admin/balance_admin.py +166 -632
  39. django_cfg/apps/payments/admin/currencies_admin.py +235 -607
  40. django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
  41. django_cfg/apps/payments/admin/filters.py +83 -3
  42. django_cfg/apps/payments/admin/networks_admin.py +269 -0
  43. django_cfg/apps/payments/admin/payments_admin.py +183 -460
  44. django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
  45. django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
  46. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
  47. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
  48. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
  49. django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
  50. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
  51. django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
  52. django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
  53. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
  54. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
  55. django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
  56. django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
  57. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
  58. django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
  59. django_cfg/apps/payments/config/__init__.py +14 -15
  60. django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
  61. django_cfg/apps/payments/config/helpers.py +8 -13
  62. django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
  63. django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
  64. django_cfg/apps/payments/middleware/api_access.py +32 -6
  65. django_cfg/apps/payments/migrations/0001_initial.py +33 -46
  66. django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
  67. django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
  68. django_cfg/apps/payments/models/balance.py +12 -0
  69. django_cfg/apps/payments/models/currencies.py +106 -32
  70. django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
  71. django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
  72. django_cfg/apps/payments/models/payments.py +94 -0
  73. django_cfg/apps/payments/services/core/base.py +4 -4
  74. django_cfg/apps/payments/services/core/currency_service.py +35 -28
  75. django_cfg/apps/payments/services/core/payment_service.py +266 -39
  76. django_cfg/apps/payments/services/providers/__init__.py +3 -0
  77. django_cfg/apps/payments/services/providers/base.py +303 -41
  78. django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
  79. django_cfg/apps/payments/services/providers/models/base.py +145 -0
  80. django_cfg/apps/payments/services/providers/models/providers.py +87 -0
  81. django_cfg/apps/payments/services/providers/models/universal.py +48 -0
  82. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
  83. django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
  84. django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
  85. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
  86. django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
  87. django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
  88. django_cfg/apps/payments/services/providers/registry.py +9 -37
  89. django_cfg/apps/payments/services/providers/sync_service.py +277 -0
  90. django_cfg/apps/payments/services/types/requests.py +19 -7
  91. django_cfg/apps/payments/signals/payment_signals.py +31 -2
  92. django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
  93. django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
  94. django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
  95. django_cfg/apps/payments/tasks/__init__.py +39 -0
  96. django_cfg/apps/payments/tasks/types.py +73 -0
  97. django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
  98. django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
  99. django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
  100. django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
  101. django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
  102. django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
  103. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
  104. django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
  105. django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
  106. django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
  107. django_cfg/apps/payments/urls.py +3 -2
  108. django_cfg/apps/payments/urls_admin.py +1 -1
  109. django_cfg/apps/payments/views/api/currencies.py +8 -5
  110. django_cfg/apps/payments/views/overview/services.py +2 -2
  111. django_cfg/apps/payments/views/serializers/currencies.py +22 -8
  112. django_cfg/apps/support/admin/__init__.py +10 -1
  113. django_cfg/apps/support/admin/support_admin.py +338 -141
  114. django_cfg/apps/tasks/admin/__init__.py +11 -0
  115. django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
  116. django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
  117. django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
  118. django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
  119. django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
  120. django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
  121. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
  122. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
  123. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
  124. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
  125. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
  126. django_cfg/apps/tasks/tasks/__init__.py +10 -0
  127. django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
  128. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
  129. django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
  130. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
  131. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
  132. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
  133. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
  134. django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
  135. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
  136. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
  137. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
  138. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
  139. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
  140. django_cfg/apps/tasks/urls.py +2 -2
  141. django_cfg/apps/tasks/urls_admin.py +2 -2
  142. django_cfg/apps/tasks/utils/__init__.py +1 -0
  143. django_cfg/apps/tasks/utils/simulator.py +356 -0
  144. django_cfg/apps/tasks/views/__init__.py +16 -0
  145. django_cfg/apps/tasks/views/api.py +569 -0
  146. django_cfg/apps/tasks/views/dashboard.py +58 -0
  147. django_cfg/config.py +1 -1
  148. django_cfg/core/config.py +10 -5
  149. django_cfg/core/generation.py +1 -1
  150. django_cfg/core/integration/__init__.py +21 -0
  151. django_cfg/management/commands/__init__.py +13 -1
  152. django_cfg/management/commands/migrate_all.py +9 -3
  153. django_cfg/management/commands/migrator.py +11 -6
  154. django_cfg/management/commands/rundramatiq.py +3 -2
  155. django_cfg/management/commands/rundramatiq_simulator.py +430 -0
  156. django_cfg/middleware/__init__.py +0 -2
  157. django_cfg/models/api_keys.py +115 -0
  158. django_cfg/models/constance.py +0 -11
  159. django_cfg/models/payments.py +137 -3
  160. django_cfg/modules/django_admin/__init__.py +64 -0
  161. django_cfg/modules/django_admin/decorators/__init__.py +13 -0
  162. django_cfg/modules/django_admin/decorators/actions.py +106 -0
  163. django_cfg/modules/django_admin/decorators/display.py +106 -0
  164. django_cfg/modules/django_admin/mixins/__init__.py +14 -0
  165. django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
  166. django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
  167. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
  168. django_cfg/modules/django_admin/models/__init__.py +20 -0
  169. django_cfg/modules/django_admin/models/action_models.py +33 -0
  170. django_cfg/modules/django_admin/models/badge_models.py +20 -0
  171. django_cfg/modules/django_admin/models/base.py +26 -0
  172. django_cfg/modules/django_admin/models/display_models.py +31 -0
  173. django_cfg/modules/django_admin/utils/badges.py +159 -0
  174. django_cfg/modules/django_admin/utils/displays.py +247 -0
  175. django_cfg/modules/django_currency/__init__.py +2 -2
  176. django_cfg/modules/django_currency/clients/__init__.py +2 -2
  177. django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
  178. django_cfg/modules/django_currency/core/converter.py +12 -12
  179. django_cfg/modules/django_currency/database/__init__.py +2 -2
  180. django_cfg/modules/django_currency/database/database_loader.py +93 -42
  181. django_cfg/modules/django_llm/llm/client.py +10 -2
  182. django_cfg/modules/django_tasks.py +54 -21
  183. django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
  184. django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
  185. django_cfg/modules/django_unfold/dashboard.py +14 -13
  186. django_cfg/modules/django_unfold/models/config.py +1 -1
  187. django_cfg/registry/core.py +7 -9
  188. django_cfg/registry/third_party.py +2 -2
  189. django_cfg/template_archive/django_sample.zip +0 -0
  190. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
  191. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
  192. django_cfg/apps/accounts/admin/activity.py +0 -96
  193. django_cfg/apps/accounts/admin/group.py +0 -17
  194. django_cfg/apps/accounts/admin/otp.py +0 -59
  195. django_cfg/apps/accounts/admin/registration_source.py +0 -97
  196. django_cfg/apps/accounts/admin/twilio_response.py +0 -227
  197. django_cfg/apps/accounts/admin/user.py +0 -300
  198. django_cfg/apps/agents/core/agent.py +0 -281
  199. django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
  200. django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
  201. django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
  202. django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
  203. django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
  204. django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
  205. django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
  206. django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
  207. django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
  208. django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
  209. django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
  210. django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
  211. django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
  212. django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
  213. django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
  214. django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
  215. django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
  216. django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
  217. django_cfg/apps/payments/config/constance/__init__.py +0 -22
  218. django_cfg/apps/payments/config/constance/config_service.py +0 -123
  219. django_cfg/apps/payments/config/constance/fields.py +0 -69
  220. django_cfg/apps/payments/config/constance/settings.py +0 -160
  221. django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
  222. django_cfg/apps/tasks/admin.py +0 -320
  223. django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
  224. django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
  225. django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
  226. django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
  227. django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
  228. django_cfg/apps/tasks/templates/tasks/base.html +0 -96
  229. django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
  230. django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
  231. django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
  232. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
  233. django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
  234. django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
  235. django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
  236. django_cfg/apps/tasks/views.py +0 -461
  237. django_cfg/management/commands/auto_generate.py +0 -486
  238. django_cfg/middleware/static_nocache.py +0 -55
  239. django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
  240. /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
  241. /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
  242. /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
  243. /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
  244. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
  245. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
  246. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -12,7 +12,7 @@ from pydantic import BaseModel, Field, validator
12
12
  from cachetools import TTLCache
13
13
 
14
14
  # Our new clients
15
- from ..clients import YahooFinanceClient, CoinPaprikaClient
15
+ from ..clients import HybridCurrencyClient, CoinPaprikaClient
16
16
 
17
17
  logger = logging.getLogger(__name__)
18
18
 
@@ -28,11 +28,12 @@ class CoinPaprikaCoinInfo(BaseModel):
28
28
  name: str = Field(description="Full coin name")
29
29
 
30
30
 
31
- class YahooFinanceCurrencyInfo(BaseModel):
32
- """Single fiat currency information."""
31
+ class HybridCurrencyInfo(BaseModel):
32
+ """Single currency information from hybrid client."""
33
33
  code: str = Field(description="Currency code (e.g., USD)")
34
34
  name: str = Field(description="Full currency name")
35
35
  symbol: str = Field(default="", description="Currency symbol (e.g., $)")
36
+ currency_type: str = Field(description="Currency type (fiat, crypto, metal)")
36
37
 
37
38
 
38
39
  class CurrencyRateInfo(BaseModel):
@@ -93,7 +94,7 @@ class CurrencyDatabaseLoader:
93
94
  self.config = config or DatabaseLoaderConfig()
94
95
 
95
96
  # Initialize clients
96
- self.yahoo = YahooFinanceClient(cache_ttl=self.config.cache_ttl_hours * 3600)
97
+ self.hybrid = HybridCurrencyClient(cache_ttl=self.config.cache_ttl_hours * 3600)
97
98
  self.coinpaprika = CoinPaprikaClient(cache_ttl=self.config.cache_ttl_hours * 3600)
98
99
 
99
100
  # Rate limiters
@@ -107,36 +108,48 @@ class CurrencyDatabaseLoader:
107
108
 
108
109
  logger.info(f"Initialized CurrencyDatabaseLoader with config: {self.config}")
109
110
 
110
- def get_fiat_currency_list(self) -> List[YahooFinanceCurrencyInfo]:
111
+ def get_hybrid_currency_list(self) -> List[HybridCurrencyInfo]:
111
112
  """
112
- Get list of supported fiat currencies.
113
+ Get list of supported currencies from hybrid client.
113
114
 
114
115
  Returns:
115
- List of fiat currency info objects
116
+ List of currency info objects
116
117
  """
117
- cache_key = "fiat_currencies"
118
+ cache_key = "hybrid_currencies"
118
119
 
119
120
  if cache_key in self.fiat_cache:
120
- logger.debug("Retrieved fiat currencies from cache")
121
+ logger.debug("Retrieved hybrid currencies from cache")
121
122
  return self.fiat_cache[cache_key]
122
123
 
123
- # Get supported currencies from Yahoo
124
- supported_currencies = self.yahoo.get_all_supported_currencies()
124
+ # Get supported currencies from Hybrid client
125
+ supported_currencies = self.hybrid.get_all_supported_currencies()
125
126
 
126
- # Convert to our format and limit count
127
- fiat_currencies = []
128
- for code, name in list(supported_currencies.items())[:self.config.max_fiat_currencies]:
129
- currency_info = YahooFinanceCurrencyInfo(
127
+ # Convert to our format
128
+ hybrid_currencies = []
129
+ for code, name in supported_currencies.items():
130
+ # Determine currency type based on code
131
+ if code in ['BTC', 'ETH', 'BNB', 'XRP', 'ADA', 'SOL', 'DOT', 'MATIC',
132
+ 'LTC', 'BCH', 'LINK', 'UNI', 'ATOM', 'XLM', 'VET', 'FIL',
133
+ 'TRX', 'ETC', 'THETA', 'AAVE', 'MKR', 'COMP', 'SUSHI',
134
+ 'USDT', 'USDC', 'BUSD', 'DAI', 'TUSD', 'USDP']:
135
+ currency_type = "crypto"
136
+ elif code in ['XAU', 'XAG', 'XPT', 'XPD']:
137
+ currency_type = "metal"
138
+ else:
139
+ currency_type = "fiat"
140
+
141
+ currency_info = HybridCurrencyInfo(
130
142
  code=code,
131
143
  name=name,
132
- symbol="" # Yahoo doesn't provide symbols
144
+ symbol="$" if code == "USD" else "", # Basic symbol mapping
145
+ currency_type=currency_type
133
146
  )
134
- fiat_currencies.append(currency_info)
147
+ hybrid_currencies.append(currency_info)
135
148
 
136
- self.fiat_cache[cache_key] = fiat_currencies
137
- logger.info(f"Loaded {len(fiat_currencies)} fiat currencies")
149
+ self.fiat_cache[cache_key] = hybrid_currencies
150
+ logger.info(f"Loaded {len(hybrid_currencies)} currencies from hybrid client")
138
151
 
139
- return fiat_currencies
152
+ return hybrid_currencies
140
153
 
141
154
  def get_cryptocurrency_list(self) -> List[CoinPaprikaCoinInfo]:
142
155
  """
@@ -233,7 +246,7 @@ class CurrencyDatabaseLoader:
233
246
  self.yahoo_limiter()
234
247
 
235
248
  try:
236
- rate_obj = self.yahoo.fetch_rate(base, quote)
249
+ rate_obj = self.hybrid.fetch_rate(base, quote)
237
250
  return rate_obj.rate
238
251
  except Exception as e:
239
252
  logger.debug(f"Failed to get fiat rate {base}/{quote}: {e}")
@@ -241,48 +254,72 @@ class CurrencyDatabaseLoader:
241
254
 
242
255
  def build_currency_database_data(self) -> List[CurrencyRateInfo]:
243
256
  """
244
- Build complete currency database data combining fiat and crypto.
257
+ Build complete currency database data using hybrid client.
245
258
 
246
259
  Returns:
247
260
  List of currency rate info objects
248
261
  """
249
262
  currencies = []
250
263
 
251
- # Get fiat currencies
252
- logger.info("Loading fiat currencies...")
253
- fiat_currencies = self.get_fiat_currency_list()
264
+ # Get currencies from hybrid client
265
+ logger.info("Loading currencies from hybrid client...")
266
+ hybrid_currencies = self.get_hybrid_currency_list()
254
267
 
255
- for fiat in fiat_currencies:
268
+ for currency in hybrid_currencies:
256
269
  # Get USD rate
257
- if fiat.code == 'USD':
270
+ if currency.code == 'USD':
258
271
  usd_rate = 1.0
259
272
  else:
260
- usd_rate = self.get_fiat_rate(fiat.code, 'USD')
273
+ usd_rate = self.get_fiat_rate(currency.code, 'USD')
261
274
  if usd_rate is None:
262
- logger.warning(f"Could not get USD rate for {fiat.code}")
275
+ logger.warning(f"Could not get USD rate for {currency.code}")
263
276
  continue
264
277
 
278
+ # Set decimal places based on currency type and value
279
+ if currency.currency_type == "fiat":
280
+ decimal_places = 2
281
+ min_payment = 1.0
282
+ elif currency.currency_type == "crypto":
283
+ if usd_rate >= 1:
284
+ decimal_places = 2
285
+ elif usd_rate >= 0.01:
286
+ decimal_places = 4
287
+ else:
288
+ decimal_places = 8
289
+ min_payment = max(1.0 / usd_rate, 0.000001)
290
+ else: # metal
291
+ decimal_places = 4
292
+ min_payment = 0.001
293
+
265
294
  currency_info = CurrencyRateInfo(
266
- code=fiat.code,
267
- name=fiat.name,
268
- symbol=fiat.symbol or "$" if fiat.code == "USD" else "",
269
- currency_type="fiat",
270
- decimal_places=2,
295
+ code=currency.code,
296
+ name=currency.name,
297
+ symbol=currency.symbol,
298
+ currency_type=currency.currency_type,
299
+ decimal_places=decimal_places,
271
300
  usd_rate=usd_rate,
272
- min_payment_amount=1.0
301
+ min_payment_amount=min_payment
273
302
  )
274
303
  currencies.append(currency_info)
275
304
 
276
- # Get cryptocurrencies
277
- logger.info("Loading cryptocurrencies...")
305
+ # Get additional cryptocurrencies from CoinPaprika (for extended crypto coverage)
306
+ logger.info("Loading additional cryptocurrencies from CoinPaprika...")
278
307
  crypto_currencies = self.get_cryptocurrency_list()
279
308
 
309
+ # Filter out cryptos that are already in hybrid client
310
+ hybrid_crypto_codes = {c.code for c in hybrid_currencies if c.currency_type == "crypto"}
311
+
280
312
  if crypto_currencies:
281
313
  # Get rates for all cryptos
282
- crypto_symbols = [crypto.symbol for crypto in crypto_currencies]
314
+ crypto_symbols = [crypto.symbol for crypto in crypto_currencies
315
+ if crypto.symbol not in hybrid_crypto_codes]
283
316
  rates = self.get_currency_rates(crypto_symbols, 'usd')
284
317
 
285
318
  for crypto in crypto_currencies:
319
+ # Skip if already covered by hybrid client
320
+ if crypto.symbol in hybrid_crypto_codes:
321
+ continue
322
+
286
323
  if crypto.symbol in rates:
287
324
  usd_rate = rates[crypto.symbol]
288
325
 
@@ -313,13 +350,27 @@ class CurrencyDatabaseLoader:
313
350
 
314
351
  def get_statistics(self) -> Dict[str, int]:
315
352
  """Get loader statistics."""
316
- fiat_count = len(self.get_fiat_currency_list())
317
- crypto_count = len(self.get_cryptocurrency_list())
353
+ hybrid_currencies = self.get_hybrid_currency_list()
354
+ coinpaprika_cryptos = self.get_cryptocurrency_list()
355
+
356
+ # Count by type from hybrid client
357
+ fiat_count = len([c for c in hybrid_currencies if c.currency_type == "fiat"])
358
+ hybrid_crypto_count = len([c for c in hybrid_currencies if c.currency_type == "crypto"])
359
+ metal_count = len([c for c in hybrid_currencies if c.currency_type == "metal"])
360
+
361
+ # Additional cryptos from CoinPaprika (excluding duplicates)
362
+ hybrid_crypto_codes = {c.code for c in hybrid_currencies if c.currency_type == "crypto"}
363
+ additional_crypto_count = len([c for c in coinpaprika_cryptos if c.symbol not in hybrid_crypto_codes])
364
+
365
+ total_crypto_count = hybrid_crypto_count + additional_crypto_count
318
366
 
319
367
  return {
320
368
  'total_fiat_currencies': fiat_count,
321
- 'total_cryptocurrencies': crypto_count,
322
- 'total_currencies': fiat_count + crypto_count,
369
+ 'total_cryptocurrencies': total_crypto_count,
370
+ 'total_metal_currencies': metal_count,
371
+ 'hybrid_crypto_currencies': hybrid_crypto_count,
372
+ 'coinpaprika_crypto_currencies': additional_crypto_count,
373
+ 'total_currencies': fiat_count + total_crypto_count + metal_count,
323
374
  'max_cryptocurrencies': self.config.max_cryptocurrencies,
324
375
  'max_fiat_currencies': self.config.max_fiat_currencies,
325
376
  'min_market_cap_usd': self.config.min_market_cap_usd
@@ -76,8 +76,16 @@ class LLMClient(BaseCfgModule):
76
76
  django_config = self.get_config()
77
77
  if django_config:
78
78
  if apikey_openai is None:
79
- apikey_openai = getattr(django_config, 'openai_api_key', None)
80
- # Add other API keys as needed
79
+ # Try new api_keys system first, then fallback to old attribute
80
+ if hasattr(django_config, 'api_keys') and django_config.api_keys:
81
+ apikey_openai = django_config.api_keys.get_openai_key()
82
+ else:
83
+ apikey_openai = getattr(django_config, 'openai_api_key', None)
84
+
85
+ if apikey_openrouter is None:
86
+ # Try new api_keys system first
87
+ if hasattr(django_config, 'api_keys') and django_config.api_keys:
88
+ apikey_openrouter = django_config.api_keys.get_openrouter_key()
81
89
 
82
90
  # Store API keys and preferred provider
83
91
  self.apikey_openrouter = apikey_openrouter
@@ -86,29 +86,49 @@ class DjangoTasks(BaseCfgModule):
86
86
  return True
87
87
 
88
88
  def get_redis_url(self) -> Optional[str]:
89
- """Get Redis URL from Django-CFG cache configuration."""
89
+ """Get Redis URL using the same logic as Dramatiq settings generation."""
90
90
  if self._redis_url is None:
91
+ # Use BaseCfgModule to get config (same as generate_dramatiq_settings_from_config)
92
+ config = self.get_config()
93
+
94
+ if not config:
95
+ raise RuntimeError("No Django-CFG configuration available")
96
+
97
+ # Get Redis URL from cache config (same logic as generate_dramatiq_settings_from_config)
98
+ if hasattr(config, 'cache_default') and config.cache_default:
99
+ self._redis_url = getattr(config.cache_default, 'redis_url', None)
100
+ if self._redis_url:
101
+ logger.debug(f"Got Redis URL from cache config: {self._redis_url}")
102
+ return self._redis_url
103
+
104
+ # If no cache_default, try to get from Django cache settings
91
105
  try:
92
- from django_cfg.core.config import get_current_config
93
- django_config = get_current_config()
94
-
95
- if not django_config:
96
- try:
97
- from api.config import config
98
- django_config = config
99
- except ImportError:
100
- logger.warning("Could not import config from api.config")
101
-
102
- if django_config and hasattr(django_config, 'cache_default') and django_config.cache_default:
103
- cache_config = django_config.cache_default
104
- if hasattr(cache_config, 'redis_url') and cache_config.redis_url:
105
- self._redis_url = cache_config.redis_url
106
- logger.debug(f"Got Redis URL: {self._redis_url}")
107
- elif hasattr(cache_config, 'location') and cache_config.location:
108
- self._redis_url = cache_config.location
109
- logger.debug(f"Got Redis URL from location: {self._redis_url}")
106
+ from django.conf import settings
107
+ if hasattr(settings, 'CACHES') and 'default' in settings.CACHES:
108
+ cache_config = settings.CACHES['default']
109
+ if cache_config.get('BACKEND') == 'django_redis.cache.RedisCache':
110
+ self._redis_url = cache_config.get('LOCATION')
111
+ if self._redis_url:
112
+ logger.debug(f"Got Redis URL from Django cache settings: {self._redis_url}")
113
+ return self._redis_url
110
114
  except Exception as e:
111
- logger.warning(f"Failed to get Redis URL: {e}")
115
+ logger.debug(f"Could not get Redis URL from Django settings: {e}")
116
+
117
+ # Try to get from DRAMATIQ_BROKER settings
118
+ try:
119
+ from django.conf import settings
120
+ if hasattr(settings, 'DRAMATIQ_BROKER'):
121
+ dramatiq_config = settings.DRAMATIQ_BROKER
122
+ if isinstance(dramatiq_config, dict) and 'OPTIONS' in dramatiq_config:
123
+ self._redis_url = dramatiq_config['OPTIONS'].get('url')
124
+ if self._redis_url:
125
+ logger.debug(f"Got Redis URL from DRAMATIQ_BROKER settings: {self._redis_url}")
126
+ return self._redis_url
127
+ except Exception as e:
128
+ logger.debug(f"Could not get Redis URL from DRAMATIQ_BROKER settings: {e}")
129
+
130
+ # If still no Redis URL found, raise error (no fallbacks)
131
+ raise RuntimeError("No Redis URL found in cache configuration, Django settings, or DRAMATIQ_BROKER")
112
132
 
113
133
  return self._redis_url
114
134
 
@@ -120,10 +140,23 @@ class DjangoTasks(BaseCfgModule):
120
140
 
121
141
  try:
122
142
  parsed = urlparse(redis_url)
143
+
144
+ # Extract database from URL path, fallback to config or default
145
+ db = 1 # Default
146
+ if parsed.path and parsed.path != "/":
147
+ try:
148
+ db = int(parsed.path.lstrip('/'))
149
+ except ValueError:
150
+ pass
151
+ elif self.config and self.config.dramatiq:
152
+ db = self.config.dramatiq.redis_db
153
+
154
+ logger.debug(f"Using Redis DB: {db} from URL: {redis_url}")
155
+
123
156
  return redis.Redis(
124
157
  host=parsed.hostname or 'localhost',
125
158
  port=parsed.port or 6379,
126
- db=self.config.dramatiq.redis_db if self.config else 1,
159
+ db=db,
127
160
  password=parsed.password,
128
161
  socket_timeout=5
129
162
  )
@@ -6,7 +6,7 @@ import logging
6
6
  from typing import List
7
7
 
8
8
  from ..models.dashboard import QuickAction
9
- from ..icons import Icons
9
+ from django_cfg.modules.django_admin.icons import Icons
10
10
  from .base import get_user_admin_urls
11
11
 
12
12
  logger = logging.getLogger(__name__)
@@ -12,7 +12,7 @@ from django.contrib.auth import get_user_model
12
12
  from django.apps import apps
13
13
 
14
14
  from ..models.dashboard import StatCard
15
- from ..icons import Icons
15
+ from django_cfg.modules.django_admin.icons import Icons
16
16
 
17
17
  logger = logging.getLogger(__name__)
18
18
 
@@ -9,7 +9,7 @@ from typing import List, Dict, Any, Optional
9
9
  from django.templatetags.static import static
10
10
  from django.urls import reverse_lazy
11
11
  from ..base import BaseCfgModule
12
- from .icons import Icons
12
+ from django_cfg.modules.django_admin.icons import Icons
13
13
  from .models.navigation import NavigationSection, NavigationItem
14
14
  from .models.dashboard import StatCard, StatsCardsWidget
15
15
 
@@ -176,29 +176,30 @@ class DashboardManager(BaseCfgModule):
176
176
 
177
177
  # Always show basic admin models (even if payments functionality is disabled)
178
178
  payments_items.extend([
179
- NavigationItem(title="Payments", icon=Icons.ACCOUNT_BALANCE, link="/admin/payments/universalpayment/"),
179
+ NavigationItem(title="Universal Payments", icon=Icons.ACCOUNT_BALANCE, link="/admin/payments/universalpayment/"),
180
180
  NavigationItem(title="Currencies", icon=Icons.CURRENCY_BITCOIN, link="/admin/payments/currency/"),
181
- NavigationItem(title="Currency Networks", icon=Icons.LINK, link="/admin/payments/network/"),
181
+ NavigationItem(title="Networks", icon=Icons.LINK, link="/admin/payments/network/"),
182
182
  NavigationItem(title="Provider Currencies", icon=Icons.ACCOUNT_CIRCLE, link="/admin/payments/providercurrency/"),
183
183
  ])
184
184
 
185
185
  # Add advanced features only if payments functionality is enabled
186
186
  if config.enabled:
187
- payments_items.append(
188
- NavigationItem(title="Webhook Dashboard", icon=Icons.WEBHOOK, link="/cfg/admin/django_cfg_payments/admin/webhooks/")
189
- )
190
- payments_items.append(
191
- NavigationItem(title="Create Payment", icon=Icons.ADD, link="/cfg/admin/django_cfg_payments/admin/payments/create/")
192
- )
193
- payments_items.append(
194
- NavigationItem(title="Currency Converter", icon=Icons.CURRENCY_EXCHANGE, link="/cfg/admin/django_cfg_payments/admin/tools/converter/")
195
- )
187
+ # payments_items.append(
188
+ # NavigationItem(title="Webhook Dashboard", icon=Icons.WEBHOOK, link="/cfg/admin/django_cfg_payments/admin/webhooks/")
189
+ # )
190
+ # payments_items.append(
191
+ # NavigationItem(title="Create Payment", icon=Icons.ADD, link="/cfg/admin/django_cfg_payments/admin/payments/create/")
192
+ # )
193
+ # payments_items.append(
194
+ # NavigationItem(title="Currency Converter", icon=Icons.CURRENCY_EXCHANGE, link="/cfg/admin/django_cfg_payments/admin/tools/converter/")
195
+ # )
196
196
 
197
197
  # Show subscription features only if enabled
198
198
  if config.show_subscription_management():
199
199
  payments_items.extend([
200
200
  NavigationItem(title="Subscriptions", icon=Icons.PERSON_ADD, link="/admin/payments/subscription/"),
201
201
  NavigationItem(title="Tariffs", icon=Icons.PRICE_CHANGE, link="/admin/payments/tariff/"),
202
+ NavigationItem(title="Tariff Endpoint Groups", icon=Icons.GROUP, link="/admin/payments/tariffendpointgroup/"),
202
203
  ])
203
204
 
204
205
  # Show API management only if enabled
@@ -223,7 +224,7 @@ class DashboardManager(BaseCfgModule):
223
224
  # Fallback
224
225
  payments_items = [
225
226
  NavigationItem(title="Payment Dashboard", icon=Icons.DASHBOARD, link="/cfg/admin/django_cfg_payments/admin/"),
226
- NavigationItem(title="Payments", icon=Icons.ACCOUNT_BALANCE, link="/admin/payments/universalpayment/"),
227
+ NavigationItem(title="Universal Payments", icon=Icons.ACCOUNT_BALANCE, link="/admin/payments/universalpayment/"),
227
228
  ]
228
229
 
229
230
  navigation_sections.append(NavigationSection(
@@ -10,7 +10,7 @@ from ...base import BaseCfgModule
10
10
  from .navigation import NavigationSection
11
11
  from .dropdown import SiteDropdownItem
12
12
  from .tabs import TabConfiguration
13
- from ..icons import Icons
13
+ from django_cfg.modules.django_admin.icons import Icons
14
14
  import logging
15
15
 
16
16
  logger = logging.getLogger(__name__)
@@ -35,6 +35,9 @@ CORE_REGISTRY = {
35
35
  # Limits models
36
36
  "LimitsConfig": ("django_cfg.models.limits", "LimitsConfig"),
37
37
 
38
+ # API Keys models
39
+ "ApiKeys": ("django_cfg.models.api_keys", "ApiKeys"),
40
+
38
41
  # JWT models
39
42
  "JWTConfig": ("django_cfg.models.jwt", "JWTConfig"),
40
43
 
@@ -42,16 +45,11 @@ CORE_REGISTRY = {
42
45
  "TaskConfig": ("django_cfg.models.tasks", "TaskConfig"),
43
46
  "DramatiqConfig": ("django_cfg.models.tasks", "DramatiqConfig"),
44
47
 
45
- # Payment system models
48
+ # Payment system models (BaseCfgAutoModule)
46
49
  "PaymentsConfig": ("django_cfg.models.payments", "PaymentsConfig"),
47
- "PaymentProviderConfig": ("django_cfg.models.payments", "PaymentProviderConfig"),
48
- "NowPaymentsConfig": ("django_cfg.models.payments", "NowPaymentsConfig"),
49
- "CryptAPIConfig": ("django_cfg.models.payments", "CryptAPIConfig"),
50
- "StripeConfig": ("django_cfg.models.payments", "StripeConfig"),
51
- "create_nowpayments_config": ("django_cfg.models.payments", "create_nowpayments_config"),
52
- "create_cryptapi_config": ("django_cfg.models.payments", "create_cryptapi_config"),
53
- "create_stripe_config": ("django_cfg.models.payments", "create_stripe_config"),
54
- "create_cryptomus_config": ("django_cfg.models.payments", "create_cryptomus_config"),
50
+ "ProviderAPIKeysConfig": ("django_cfg.models.payments", "ProviderAPIKeysConfig"),
51
+ "BaseProviderConfig": ("django_cfg.models.payments", "BaseProviderConfig"),
52
+ "NowPaymentsProviderConfig": ("django_cfg.models.payments", "NowPaymentsProviderConfig"),
55
53
 
56
54
  # Pagination classes
57
55
  "DefaultPagination": ("django_cfg.middleware.pagination", "DefaultPagination"),
@@ -47,6 +47,6 @@ THIRD_PARTY_REGISTRY = {
47
47
  "NgrokTunnelConfig": ("django_cfg.models.ngrok", "NgrokTunnelConfig"),
48
48
 
49
49
  # Material Icons
50
- "Icons": ("django_cfg.modules.django_unfold.icons", "Icons"),
51
- "IconCategories": ("django_cfg.modules.django_unfold.icons", "IconCategories"),
50
+ "Icons": ("django_cfg.modules.django_admin.icons", "Icons"),
51
+ "IconCategories": ("django_cfg.modules.django_admin.icons", "IconCategories"),
52
52
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-cfg
3
- Version: 1.3.7
3
+ Version: 1.3.11
4
4
  Summary: 🚀 Next-gen Django configuration: type-safety, AI features, blazing-fast setup, and automated best practices — all in one.
5
5
  Project-URL: Homepage, https://djangocfg.com
6
6
  Project-URL: Documentation, https://docs.djangocfg.com
@@ -60,6 +60,7 @@ Requires-Dist: drf-spectacular<1.0,>=0.28.0
60
60
  Requires-Dist: hiredis<4.0,>=2.0.0
61
61
  Requires-Dist: loguru<1.0,>=0.7.0
62
62
  Requires-Dist: lxml<7.0,>=6.0.0
63
+ Requires-Dist: mypy<2.0.0,>=1.18.2
63
64
  Requires-Dist: ngrok>=1.5.1; python_version >= '3.12'
64
65
  Requires-Dist: openai<2.0,>=1.107.0
65
66
  Requires-Dist: pgvector<1.0,>=0.4.0