django-cfg 1.4.20__py3-none-any.whl → 1.4.23__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 (794) hide show
  1. django_cfg/__init__.py +4 -4
  2. django_cfg/apps/accounts/__init__.py +1 -1
  3. django_cfg/apps/accounts/__models.py +30 -29
  4. django_cfg/apps/accounts/admin/__init__.py +14 -3
  5. django_cfg/apps/accounts/admin/activity_admin.py +19 -19
  6. django_cfg/apps/accounts/admin/filters.py +7 -6
  7. django_cfg/apps/accounts/admin/group_admin.py +10 -16
  8. django_cfg/apps/accounts/admin/inlines.py +21 -19
  9. django_cfg/apps/accounts/admin/otp_admin.py +12 -12
  10. django_cfg/apps/accounts/admin/registration_admin.py +24 -24
  11. django_cfg/apps/accounts/admin/resources.py +49 -48
  12. django_cfg/apps/accounts/admin/twilio_admin.py +37 -37
  13. django_cfg/apps/accounts/admin/user_admin.py +45 -41
  14. django_cfg/apps/accounts/management/commands/otp_test.py +11 -11
  15. django_cfg/apps/accounts/managers/__init__.py +1 -1
  16. django_cfg/apps/accounts/managers/user_manager.py +6 -7
  17. django_cfg/apps/accounts/migrations/0001_initial.py +3 -2
  18. django_cfg/apps/accounts/models/__init__.py +15 -16
  19. django_cfg/apps/accounts/models/activity.py +5 -5
  20. django_cfg/apps/accounts/models/integrations.py +15 -15
  21. django_cfg/apps/accounts/models/registration.py +3 -2
  22. django_cfg/apps/accounts/models/user.py +3 -2
  23. django_cfg/apps/accounts/serializers/__init__.py +10 -3
  24. django_cfg/apps/accounts/serializers/otp.py +5 -4
  25. django_cfg/apps/accounts/serializers/profile.py +4 -5
  26. django_cfg/apps/accounts/serializers/webhook.py +13 -13
  27. django_cfg/apps/accounts/services/activity_service.py +13 -12
  28. django_cfg/apps/accounts/services/otp_service.py +16 -14
  29. django_cfg/apps/accounts/signals.py +18 -16
  30. django_cfg/apps/accounts/urls.py +10 -5
  31. django_cfg/apps/accounts/utils/notifications.py +22 -22
  32. django_cfg/apps/accounts/views/__init__.py +1 -1
  33. django_cfg/apps/accounts/views/otp.py +15 -14
  34. django_cfg/apps/accounts/views/profile.py +14 -10
  35. django_cfg/apps/accounts/views/webhook.py +46 -48
  36. django_cfg/apps/agents/__init__.py +3 -3
  37. django_cfg/apps/agents/admin/__init__.py +1 -1
  38. django_cfg/apps/agents/admin/execution_admin.py +68 -72
  39. django_cfg/apps/agents/admin/registry_admin.py +50 -54
  40. django_cfg/apps/agents/admin/toolsets_admin.py +63 -67
  41. django_cfg/apps/agents/apps.py +3 -3
  42. django_cfg/apps/agents/core/__init__.py +4 -4
  43. django_cfg/apps/agents/core/dependencies.py +24 -23
  44. django_cfg/apps/agents/core/django_agent.py +41 -39
  45. django_cfg/apps/agents/core/exceptions.py +12 -12
  46. django_cfg/apps/agents/core/models.py +16 -15
  47. django_cfg/apps/agents/core/orchestrator.py +58 -58
  48. django_cfg/apps/agents/examples/simple_example.py +24 -19
  49. django_cfg/apps/agents/integration/__init__.py +1 -1
  50. django_cfg/apps/agents/integration/middleware.py +12 -11
  51. django_cfg/apps/agents/integration/registry.py +52 -49
  52. django_cfg/apps/agents/integration/signals.py +5 -5
  53. django_cfg/apps/agents/management/commands/create_agent.py +39 -38
  54. django_cfg/apps/agents/management/commands/orchestrator_status.py +40 -39
  55. django_cfg/apps/agents/managers/__init__.py +8 -3
  56. django_cfg/apps/agents/managers/execution.py +42 -41
  57. django_cfg/apps/agents/managers/registry.py +40 -39
  58. django_cfg/apps/agents/managers/toolsets.py +87 -86
  59. django_cfg/apps/agents/migrations/0001_initial.py +2 -1
  60. django_cfg/apps/agents/models/__init__.py +2 -2
  61. django_cfg/apps/agents/models/execution.py +43 -42
  62. django_cfg/apps/agents/models/registry.py +46 -45
  63. django_cfg/apps/agents/models/toolsets.py +63 -62
  64. django_cfg/apps/agents/patterns/__init__.py +5 -5
  65. django_cfg/apps/agents/patterns/content_agents.py +17 -16
  66. django_cfg/apps/agents/toolsets/__init__.py +3 -3
  67. django_cfg/apps/agents/toolsets/cache_toolset.py +56 -55
  68. django_cfg/apps/agents/toolsets/django_toolset.py +43 -42
  69. django_cfg/apps/agents/toolsets/file_toolset.py +64 -63
  70. django_cfg/apps/agents/toolsets/orm_toolset.py +75 -74
  71. django_cfg/apps/agents/urls.py +3 -2
  72. django_cfg/apps/api/commands/urls.py +1 -0
  73. django_cfg/apps/api/commands/views.py +23 -26
  74. django_cfg/apps/api/endpoints/checker.py +5 -4
  75. django_cfg/apps/api/endpoints/drf_views.py +2 -2
  76. django_cfg/apps/api/endpoints/tests.py +6 -5
  77. django_cfg/apps/api/endpoints/urls.py +2 -1
  78. django_cfg/apps/api/endpoints/views.py +1 -0
  79. django_cfg/apps/api/health/drf_views.py +6 -6
  80. django_cfg/apps/api/health/urls.py +2 -1
  81. django_cfg/apps/api/health/views.py +41 -41
  82. django_cfg/{modules/django_ipc_client → apps/ipc}/__init__.py +6 -6
  83. django_cfg/apps/ipc/apps.py +28 -0
  84. django_cfg/apps/ipc/serializers/__init__.py +19 -0
  85. django_cfg/apps/ipc/serializers/serializers.py +229 -0
  86. django_cfg/apps/ipc/services/__init__.py +7 -0
  87. django_cfg/apps/ipc/services/client/__init__.py +23 -0
  88. django_cfg/{modules/django_ipc_client → apps/ipc/services/client}/client.py +7 -6
  89. django_cfg/{modules/django_ipc_client → apps/ipc/services/client}/exceptions.py +1 -1
  90. django_cfg/{modules/django_ipc_client/dashboard → apps/ipc/services}/monitor.py +23 -5
  91. django_cfg/{modules/django_ipc_client/dashboard/static/django_ipc_dashboard/js/dashboard.js → apps/ipc/static/django_cfg_ipc/js/dashboard.mjs} +131 -63
  92. django_cfg/{modules/django_ipc_client/dashboard/templates/django_ipc_dashboard → apps/ipc/templates/django_cfg_ipc}/base.html +5 -10
  93. django_cfg/apps/ipc/templates/django_cfg_ipc/dashboard.html +202 -0
  94. django_cfg/apps/ipc/urls.py +21 -0
  95. django_cfg/apps/ipc/urls_admin.py +20 -0
  96. django_cfg/apps/ipc/views/__init__.py +8 -0
  97. django_cfg/apps/ipc/views/dashboard.py +15 -0
  98. django_cfg/apps/ipc/views/viewsets.py +245 -0
  99. django_cfg/apps/knowbase/admin/__init__.py +2 -2
  100. django_cfg/apps/knowbase/admin/actions/__init__.py +1 -1
  101. django_cfg/apps/knowbase/admin/actions/visibility_actions.py +2 -1
  102. django_cfg/apps/knowbase/admin/archive_admin.py +81 -84
  103. django_cfg/apps/knowbase/admin/chat_admin.py +70 -72
  104. django_cfg/apps/knowbase/admin/document_admin.py +10 -11
  105. django_cfg/apps/knowbase/admin/external_data_admin.py +69 -71
  106. django_cfg/apps/knowbase/admin/helpers/__init__.py +1 -1
  107. django_cfg/apps/knowbase/admin/helpers/configs.py +2 -2
  108. django_cfg/apps/knowbase/admin/helpers/statistics.py +1 -1
  109. django_cfg/apps/knowbase/apps.py +13 -13
  110. django_cfg/apps/knowbase/config/__init__.py +7 -6
  111. django_cfg/apps/knowbase/config/constance_fields.py +14 -12
  112. django_cfg/apps/knowbase/config/constance_settings.py +32 -31
  113. django_cfg/apps/knowbase/config/settings.py +28 -28
  114. django_cfg/apps/knowbase/examples/external_data_usage.py +35 -32
  115. django_cfg/apps/knowbase/management/commands/knowbase_stats.py +33 -32
  116. django_cfg/apps/knowbase/management/commands/setup_knowbase.py +11 -13
  117. django_cfg/apps/knowbase/managers/__init__.py +2 -2
  118. django_cfg/apps/knowbase/managers/archive.py +86 -85
  119. django_cfg/apps/knowbase/managers/base.py +5 -5
  120. django_cfg/apps/knowbase/managers/chat.py +29 -28
  121. django_cfg/apps/knowbase/managers/document.py +39 -39
  122. django_cfg/apps/knowbase/managers/external_data.py +74 -73
  123. django_cfg/apps/knowbase/migrations/0001_initial.py +2 -1
  124. django_cfg/apps/knowbase/migrations/0002_archiveitem_archiveitemchunk_documentarchive_and_more.py +2 -1
  125. django_cfg/apps/knowbase/migrations/0003_alter_documentarchive_archive_type.py +29 -0
  126. django_cfg/apps/knowbase/mixins/__init__.py +4 -4
  127. django_cfg/apps/knowbase/mixins/config/__init__.py +1 -1
  128. django_cfg/apps/knowbase/mixins/config/meta_config.py +1 -1
  129. django_cfg/apps/knowbase/mixins/config.py +19 -18
  130. django_cfg/apps/knowbase/mixins/creator.py +7 -7
  131. django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +29 -28
  132. django_cfg/apps/knowbase/mixins/external_data_mixin.py +6 -5
  133. django_cfg/apps/knowbase/mixins/generators/__init__.py +1 -1
  134. django_cfg/apps/knowbase/mixins/generators/content_generator.py +2 -2
  135. django_cfg/apps/knowbase/mixins/service.py +47 -45
  136. django_cfg/apps/knowbase/models/__init__.py +7 -7
  137. django_cfg/apps/knowbase/models/archive.py +72 -72
  138. django_cfg/apps/knowbase/models/base.py +12 -13
  139. django_cfg/apps/knowbase/models/chat.py +20 -19
  140. django_cfg/apps/knowbase/models/document.py +37 -35
  141. django_cfg/apps/knowbase/models/external_data.py +41 -42
  142. django_cfg/apps/knowbase/serializers/__init__.py +7 -7
  143. django_cfg/apps/knowbase/serializers/archive_serializers.py +50 -42
  144. django_cfg/apps/knowbase/serializers/chat_serializers.py +16 -15
  145. django_cfg/apps/knowbase/serializers/document_serializers.py +13 -12
  146. django_cfg/apps/knowbase/serializers/external_data_serializers.py +31 -31
  147. django_cfg/apps/knowbase/serializers/public_serializers.py +10 -9
  148. django_cfg/apps/knowbase/services/__init__.py +7 -7
  149. django_cfg/apps/knowbase/services/archive/__init__.py +7 -7
  150. django_cfg/apps/knowbase/services/archive/analyzers/__init__.py +1 -1
  151. django_cfg/apps/knowbase/services/archive/analyzers/tag_generator.py +1 -1
  152. django_cfg/apps/knowbase/services/archive/archive_service.py +109 -112
  153. django_cfg/apps/knowbase/services/archive/chunking/__init__.py +3 -3
  154. django_cfg/apps/knowbase/services/archive/chunking/base.py +1 -0
  155. django_cfg/apps/knowbase/services/archive/chunking/json_chunker.py +4 -3
  156. django_cfg/apps/knowbase/services/archive/chunking/markdown_chunker.py +5 -4
  157. django_cfg/apps/knowbase/services/archive/chunking/python_chunker.py +6 -5
  158. django_cfg/apps/knowbase/services/archive/chunking/text_chunker.py +4 -3
  159. django_cfg/apps/knowbase/services/archive/chunking_service.py +3 -7
  160. django_cfg/apps/knowbase/services/archive/context/__init__.py +1 -1
  161. django_cfg/apps/knowbase/services/archive/context/builders.py +2 -1
  162. django_cfg/apps/knowbase/services/archive/context/models.py +2 -1
  163. django_cfg/apps/knowbase/services/archive/exceptions.py +5 -5
  164. django_cfg/apps/knowbase/services/archive/extraction_service.py +111 -110
  165. django_cfg/apps/knowbase/services/archive/vectorization_service.py +80 -77
  166. django_cfg/apps/knowbase/services/base.py +11 -9
  167. django_cfg/apps/knowbase/services/chat_service.py +40 -39
  168. django_cfg/apps/knowbase/services/document_service.py +28 -27
  169. django_cfg/apps/knowbase/services/embedding/__init__.py +9 -9
  170. django_cfg/apps/knowbase/services/embedding/async_processor.py +38 -40
  171. django_cfg/apps/knowbase/services/embedding/batch_processor.py +45 -42
  172. django_cfg/apps/knowbase/services/embedding/batch_result.py +7 -6
  173. django_cfg/apps/knowbase/services/embedding/models.py +52 -51
  174. django_cfg/apps/knowbase/services/embedding/processors.py +24 -23
  175. django_cfg/apps/knowbase/services/embedding/utils.py +17 -17
  176. django_cfg/apps/knowbase/services/prompt_builder.py +24 -23
  177. django_cfg/apps/knowbase/services/search_service.py +52 -49
  178. django_cfg/apps/knowbase/signals/__init__.py +2 -5
  179. django_cfg/apps/knowbase/signals/archive_signals.py +35 -34
  180. django_cfg/apps/knowbase/signals/chat_signals.py +6 -5
  181. django_cfg/apps/knowbase/signals/document_signals.py +22 -22
  182. django_cfg/apps/knowbase/signals/external_data_signals.py +22 -22
  183. django_cfg/apps/knowbase/tasks/__init__.py +6 -7
  184. django_cfg/apps/knowbase/tasks/archive_tasks.py +41 -41
  185. django_cfg/apps/knowbase/tasks/document_processing.py +49 -44
  186. django_cfg/apps/knowbase/tasks/external_data_tasks.py +46 -44
  187. django_cfg/apps/knowbase/tasks/maintenance.py +26 -24
  188. django_cfg/apps/knowbase/urls.py +3 -2
  189. django_cfg/apps/knowbase/urls_admin.py +6 -3
  190. django_cfg/apps/knowbase/urls_system.py +4 -5
  191. django_cfg/apps/knowbase/utils/chunk_settings.py +22 -20
  192. django_cfg/apps/knowbase/utils/text_processing.py +76 -75
  193. django_cfg/apps/knowbase/utils/validation.py +9 -9
  194. django_cfg/apps/knowbase/views/__init__.py +5 -5
  195. django_cfg/apps/knowbase/views/archive_views.py +90 -87
  196. django_cfg/apps/knowbase/views/base.py +9 -12
  197. django_cfg/apps/knowbase/views/chat_views.py +35 -32
  198. django_cfg/apps/knowbase/views/document_views.py +27 -28
  199. django_cfg/apps/knowbase/views/public_views.py +19 -19
  200. django_cfg/apps/leads/admin/leads_admin.py +41 -45
  201. django_cfg/apps/leads/admin/resources.py +14 -14
  202. django_cfg/apps/leads/admin.py +7 -9
  203. django_cfg/apps/leads/apps.py +1 -1
  204. django_cfg/apps/leads/models.py +17 -17
  205. django_cfg/apps/leads/serializers.py +5 -4
  206. django_cfg/apps/leads/signals.py +7 -7
  207. django_cfg/apps/leads/tests.py +47 -47
  208. django_cfg/apps/leads/urls.py +2 -2
  209. django_cfg/apps/leads/views.py +11 -11
  210. django_cfg/apps/maintenance/__init__.py +3 -3
  211. django_cfg/apps/maintenance/admin/__init__.py +1 -1
  212. django_cfg/apps/maintenance/admin/api_key_admin.py +36 -36
  213. django_cfg/apps/maintenance/admin/log_admin.py +35 -37
  214. django_cfg/apps/maintenance/admin/scheduled_admin.py +47 -51
  215. django_cfg/apps/maintenance/admin/site_admin.py +49 -52
  216. django_cfg/apps/maintenance/apps.py +2 -2
  217. django_cfg/apps/maintenance/management/commands/maintenance.py +53 -52
  218. django_cfg/apps/maintenance/management/commands/process_scheduled_maintenance.py +44 -44
  219. django_cfg/apps/maintenance/management/commands/sync_cloudflare.py +32 -32
  220. django_cfg/apps/maintenance/managers/__init__.py +1 -1
  221. django_cfg/apps/maintenance/managers/cloudflare_site_manager.py +39 -38
  222. django_cfg/apps/maintenance/managers/maintenance_log_manager.py +32 -31
  223. django_cfg/apps/maintenance/migrations/0001_initial.py +1 -0
  224. django_cfg/apps/maintenance/models/__init__.py +2 -2
  225. django_cfg/apps/maintenance/models/cloudflare_api_key.py +15 -15
  226. django_cfg/apps/maintenance/models/cloudflare_site.py +24 -22
  227. django_cfg/apps/maintenance/models/maintenance_log.py +15 -14
  228. django_cfg/apps/maintenance/models/scheduled_maintenance.py +53 -52
  229. django_cfg/apps/maintenance/services/__init__.py +3 -3
  230. django_cfg/apps/maintenance/services/bulk_operations_service.py +68 -68
  231. django_cfg/apps/maintenance/services/maintenance_service.py +59 -58
  232. django_cfg/apps/maintenance/services/scheduled_maintenance_service.py +52 -52
  233. django_cfg/apps/maintenance/services/site_sync_service.py +64 -65
  234. django_cfg/apps/maintenance/utils/__init__.py +1 -1
  235. django_cfg/apps/maintenance/utils/retry_utils.py +17 -17
  236. django_cfg/apps/newsletter/admin/__init__.py +12 -16
  237. django_cfg/apps/newsletter/admin/newsletter_admin.py +90 -87
  238. django_cfg/apps/newsletter/admin/resources.py +29 -29
  239. django_cfg/apps/newsletter/admin.py +39 -32
  240. django_cfg/apps/newsletter/management/commands/test_newsletter.py +3 -3
  241. django_cfg/apps/newsletter/managers/__init__.py +1 -1
  242. django_cfg/apps/newsletter/migrations/0001_initial.py +2 -1
  243. django_cfg/apps/newsletter/models.py +34 -33
  244. django_cfg/apps/newsletter/serializers.py +13 -13
  245. django_cfg/apps/newsletter/services/email_service.py +42 -40
  246. django_cfg/apps/newsletter/signals.py +4 -3
  247. django_cfg/apps/newsletter/urls.py +7 -7
  248. django_cfg/apps/newsletter/views/__init__.py +14 -19
  249. django_cfg/apps/newsletter/views/campaigns.py +19 -19
  250. django_cfg/apps/newsletter/views/emails.py +20 -20
  251. django_cfg/apps/newsletter/views/newsletters.py +5 -5
  252. django_cfg/apps/newsletter/views/subscriptions.py +24 -24
  253. django_cfg/apps/newsletter/views/tracking.py +6 -5
  254. django_cfg/apps/payments/admin/__init__.py +6 -5
  255. django_cfg/apps/payments/admin/api_keys_admin.py +43 -45
  256. django_cfg/apps/payments/admin/balance_admin.py +41 -47
  257. django_cfg/apps/payments/admin/currencies_admin.py +60 -62
  258. django_cfg/apps/payments/admin/endpoint_groups_admin.py +14 -28
  259. django_cfg/apps/payments/admin/filters.py +59 -59
  260. django_cfg/apps/payments/admin/networks_admin.py +36 -50
  261. django_cfg/apps/payments/admin/payments_admin.py +47 -49
  262. django_cfg/apps/payments/admin/subscriptions_admin.py +30 -32
  263. django_cfg/apps/payments/admin/tariffs_admin.py +37 -42
  264. django_cfg/apps/payments/admin_interface/serializers/__init__.py +12 -13
  265. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +28 -27
  266. django_cfg/apps/payments/admin_interface/serializers/webhook_serializers.py +4 -5
  267. django_cfg/apps/payments/admin_interface/templates/payments/base.html +407 -3
  268. django_cfg/apps/payments/admin_interface/templates/payments/components/ngrok_status.html +13 -13
  269. django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +5 -1
  270. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +105 -49
  271. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +4 -1
  272. django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +16 -8
  273. django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +16 -8
  274. django_cfg/apps/payments/admin_interface/views/__init__.py +8 -9
  275. django_cfg/apps/payments/admin_interface/views/api/__init__.py +3 -3
  276. django_cfg/apps/payments/admin_interface/views/api/payments.py +52 -54
  277. django_cfg/apps/payments/admin_interface/views/api/stats.py +33 -30
  278. django_cfg/apps/payments/admin_interface/views/api/users.py +10 -11
  279. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +46 -51
  280. django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +9 -9
  281. django_cfg/apps/payments/admin_interface/views/base.py +17 -19
  282. django_cfg/apps/payments/admin_interface/views/dashboard.py +10 -10
  283. django_cfg/apps/payments/admin_interface/views/forms.py +21 -20
  284. django_cfg/apps/payments/apps.py +7 -6
  285. django_cfg/apps/payments/config/__init__.py +4 -4
  286. django_cfg/apps/payments/config/django_cfg_integration.py +22 -21
  287. django_cfg/apps/payments/config/helpers.py +14 -12
  288. django_cfg/apps/payments/management/commands/cleanup_expired_data.py +85 -86
  289. django_cfg/apps/payments/management/commands/currency_stats.py +84 -87
  290. django_cfg/apps/payments/management/commands/manage_currencies.py +59 -58
  291. django_cfg/apps/payments/management/commands/manage_providers.py +103 -105
  292. django_cfg/apps/payments/management/commands/process_pending_payments.py +67 -70
  293. django_cfg/apps/payments/management/commands/test_providers.py +83 -84
  294. django_cfg/apps/payments/middleware/__init__.py +1 -1
  295. django_cfg/apps/payments/middleware/api_access.py +77 -78
  296. django_cfg/apps/payments/middleware/rate_limiting.py +72 -72
  297. django_cfg/apps/payments/middleware/usage_tracking.py +66 -64
  298. django_cfg/apps/payments/migrations/0001_initial.py +2 -1
  299. django_cfg/apps/payments/models/__init__.py +11 -12
  300. django_cfg/apps/payments/models/api_keys.py +29 -27
  301. django_cfg/apps/payments/models/balance.py +38 -38
  302. django_cfg/apps/payments/models/base.py +12 -11
  303. django_cfg/apps/payments/models/currencies.py +53 -52
  304. django_cfg/apps/payments/models/managers/__init__.py +13 -14
  305. django_cfg/apps/payments/models/managers/api_key_managers.py +55 -53
  306. django_cfg/apps/payments/models/managers/balance_managers.py +98 -97
  307. django_cfg/apps/payments/models/managers/currency_managers.py +70 -69
  308. django_cfg/apps/payments/models/managers/payment_managers.py +113 -111
  309. django_cfg/apps/payments/models/managers/subscription_managers.py +99 -97
  310. django_cfg/apps/payments/models/payments.py +167 -73
  311. django_cfg/apps/payments/models/subscriptions.py +56 -54
  312. django_cfg/apps/payments/models/tariffs.py +35 -34
  313. django_cfg/apps/payments/services/__init__.py +33 -36
  314. django_cfg/apps/payments/services/cache/__init__.py +7 -1
  315. django_cfg/apps/payments/services/cache_service/__init__.py +22 -20
  316. django_cfg/apps/payments/services/cache_service/api_key_cache.py +6 -5
  317. django_cfg/apps/payments/services/cache_service/interfaces.py +5 -5
  318. django_cfg/apps/payments/services/cache_service/keys.py +8 -8
  319. django_cfg/apps/payments/services/cache_service/rate_limit_cache.py +8 -7
  320. django_cfg/apps/payments/services/cache_service/simple_cache.py +17 -14
  321. django_cfg/apps/payments/services/core/__init__.py +3 -3
  322. django_cfg/apps/payments/services/core/balance_service.py +69 -65
  323. django_cfg/apps/payments/services/core/base.py +25 -22
  324. django_cfg/apps/payments/services/core/currency/__init__.py +1 -1
  325. django_cfg/apps/payments/services/core/currency/currency_converter.py +2 -0
  326. django_cfg/apps/payments/services/core/currency_service.py +68 -66
  327. django_cfg/apps/payments/services/core/operations/__init__.py +1 -1
  328. django_cfg/apps/payments/services/core/operations/payment_canceller.py +2 -1
  329. django_cfg/apps/payments/services/core/operations/payment_creator.py +2 -1
  330. django_cfg/apps/payments/services/core/operations/status_checker.py +2 -1
  331. django_cfg/apps/payments/services/core/payment_service.py +10 -7
  332. django_cfg/apps/payments/services/core/providers/provider_client.py +2 -2
  333. django_cfg/apps/payments/services/core/subscription_service.py +77 -74
  334. django_cfg/apps/payments/services/core/utils/data_converter.py +1 -0
  335. django_cfg/apps/payments/services/core/utils/statistics_calculator.py +1 -0
  336. django_cfg/apps/payments/services/core/webhook_service.py +67 -63
  337. django_cfg/apps/payments/services/integrations/__init__.py +3 -3
  338. django_cfg/apps/payments/services/integrations/ngrok_service.py +1 -0
  339. django_cfg/apps/payments/services/integrations/providers_config.py +3 -2
  340. django_cfg/apps/payments/services/providers/base.py +59 -57
  341. django_cfg/apps/payments/services/providers/models/__init__.py +7 -14
  342. django_cfg/apps/payments/services/providers/models/base.py +15 -15
  343. django_cfg/apps/payments/services/providers/models/providers.py +13 -12
  344. django_cfg/apps/payments/services/providers/models/universal.py +6 -5
  345. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +4 -4
  346. django_cfg/apps/payments/services/providers/nowpayments/config.py +9 -8
  347. django_cfg/apps/payments/services/providers/nowpayments/models.py +15 -15
  348. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/__init__.py +2 -2
  349. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/patterns.py +26 -26
  350. django_cfg/apps/payments/services/providers/nowpayments/parsers/parser.py +3 -2
  351. django_cfg/apps/payments/services/providers/nowpayments/provider.py +95 -99
  352. django_cfg/apps/payments/services/providers/nowpayments/sync.py +41 -40
  353. django_cfg/apps/payments/services/providers/registry.py +65 -63
  354. django_cfg/apps/payments/services/providers/sync_service.py +50 -50
  355. django_cfg/apps/payments/services/types/__init__.py +21 -22
  356. django_cfg/apps/payments/services/types/data.py +14 -13
  357. django_cfg/apps/payments/services/types/requests.py +21 -22
  358. django_cfg/apps/payments/services/types/responses.py +16 -15
  359. django_cfg/apps/payments/services/types/webhooks.py +30 -30
  360. django_cfg/apps/payments/signals/__init__.py +4 -6
  361. django_cfg/apps/payments/signals/api_key_signals.py +36 -35
  362. django_cfg/apps/payments/signals/balance_signals.py +28 -26
  363. django_cfg/apps/payments/signals/payment_signals.py +29 -28
  364. django_cfg/apps/payments/signals/subscription_signals.py +39 -38
  365. django_cfg/apps/payments/static/payments/js/ngrok-status.js +12 -8
  366. django_cfg/apps/payments/static/payments/js/payment-detail.js +1 -1
  367. django_cfg/apps/payments/static/payments/js/payment-form.js +3 -3
  368. django_cfg/apps/payments/static/payments/js/payment-list.js +13 -6
  369. django_cfg/apps/payments/static/payments/js/webhook-dashboard-mjs.js +241 -0
  370. django_cfg/apps/payments/tasks/__init__.py +11 -12
  371. django_cfg/apps/payments/tasks/types.py +10 -9
  372. django_cfg/apps/payments/tasks/usage_tracking.py +44 -46
  373. django_cfg/apps/payments/templatetags/payment_tags.py +27 -27
  374. django_cfg/apps/payments/urls.py +31 -14
  375. django_cfg/apps/payments/urls_admin.py +10 -10
  376. django_cfg/apps/payments/views/api/__init__.py +32 -33
  377. django_cfg/apps/payments/views/api/api_keys.py +62 -62
  378. django_cfg/apps/payments/views/api/balances.py +63 -64
  379. django_cfg/apps/payments/views/api/base.py +52 -52
  380. django_cfg/apps/payments/views/api/currencies.py +75 -63
  381. django_cfg/apps/payments/views/api/payments.py +73 -74
  382. django_cfg/apps/payments/views/api/subscriptions.py +71 -72
  383. django_cfg/apps/payments/views/api/webhooks.py +85 -84
  384. django_cfg/apps/payments/views/overview/__init__.py +7 -7
  385. django_cfg/apps/payments/views/overview/serializers.py +13 -14
  386. django_cfg/apps/payments/views/overview/services.py +66 -67
  387. django_cfg/apps/payments/views/overview/urls.py +2 -1
  388. django_cfg/apps/payments/views/overview/views.py +31 -31
  389. django_cfg/apps/payments/views/serializers/__init__.py +35 -36
  390. django_cfg/apps/payments/views/serializers/api_keys.py +59 -57
  391. django_cfg/apps/payments/views/serializers/balances.py +34 -33
  392. django_cfg/apps/payments/views/serializers/currencies.py +36 -34
  393. django_cfg/apps/payments/views/serializers/payments.py +48 -47
  394. django_cfg/apps/payments/views/serializers/subscriptions.py +50 -45
  395. django_cfg/apps/payments/views/serializers/webhooks.py +17 -16
  396. django_cfg/apps/support/admin/__init__.py +3 -3
  397. django_cfg/apps/support/admin/resources.py +26 -26
  398. django_cfg/apps/support/admin/support_admin.py +44 -48
  399. django_cfg/apps/support/admin.py +16 -15
  400. django_cfg/apps/support/apps.py +1 -1
  401. django_cfg/apps/support/managers/message_manager.py +4 -4
  402. django_cfg/apps/support/managers/ticket_manager.py +13 -12
  403. django_cfg/apps/support/migrations/0001_initial.py +2 -1
  404. django_cfg/apps/support/models.py +3 -1
  405. django_cfg/apps/support/serializers.py +4 -2
  406. django_cfg/apps/support/signals.py +12 -10
  407. django_cfg/apps/support/urls.py +4 -3
  408. django_cfg/apps/support/utils/support_email_service.py +11 -9
  409. django_cfg/apps/support/views/__init__.py +3 -3
  410. django_cfg/apps/support/views/admin.py +9 -9
  411. django_cfg/apps/support/views/api.py +12 -13
  412. django_cfg/apps/support/views/chat.py +14 -14
  413. django_cfg/apps/tasks/admin/tasks_admin.py +65 -74
  414. django_cfg/apps/tasks/apps.py +2 -2
  415. django_cfg/apps/tasks/serializers.py +6 -6
  416. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +44 -20
  417. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +7 -5
  418. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +5 -3
  419. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +5 -3
  420. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +5 -3
  421. django_cfg/apps/tasks/tasks/demo_tasks.py +12 -11
  422. django_cfg/apps/tasks/templates/tasks/components/tasks_mjs_integration.html +269 -0
  423. django_cfg/apps/tasks/templates/tasks/pages/dashboard-improved.html +168 -0
  424. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +21 -2
  425. django_cfg/apps/tasks/urls.py +3 -2
  426. django_cfg/apps/tasks/urls_admin.py +1 -0
  427. django_cfg/apps/tasks/utils/simulator.py +49 -52
  428. django_cfg/apps/tasks/views/api.py +75 -73
  429. django_cfg/apps/tasks/views/dashboard.py +5 -4
  430. django_cfg/apps/urls.py +20 -11
  431. django_cfg/apps.py +6 -5
  432. django_cfg/cli/commands/create_project.py +7 -6
  433. django_cfg/cli/commands/info.py +25 -25
  434. django_cfg/cli/utils.py +27 -27
  435. django_cfg/config.py +1 -1
  436. django_cfg/core/__init__.py +8 -8
  437. django_cfg/core/base/config_model.py +13 -12
  438. django_cfg/core/builders/apps_builder.py +2 -2
  439. django_cfg/core/builders/middleware_builder.py +1 -1
  440. django_cfg/core/builders/security_builder.py +1 -1
  441. django_cfg/core/config.py +2 -2
  442. django_cfg/core/environment/detector.py +27 -28
  443. django_cfg/core/exceptions.py +1 -1
  444. django_cfg/core/generation/core_generators/settings.py +1 -1
  445. django_cfg/core/generation/core_generators/static.py +11 -5
  446. django_cfg/core/generation/core_generators/templates.py +1 -1
  447. django_cfg/core/generation/data_generators/__init__.py +1 -1
  448. django_cfg/core/generation/data_generators/cache.py +1 -1
  449. django_cfg/core/generation/data_generators/database.py +1 -1
  450. django_cfg/core/generation/generation.py +1 -3
  451. django_cfg/core/generation/integration_generators/__init__.py +2 -2
  452. django_cfg/core/generation/integration_generators/api.py +12 -2
  453. django_cfg/core/generation/integration_generators/sessions.py +1 -1
  454. django_cfg/core/generation/integration_generators/tailwind.py +1 -1
  455. django_cfg/core/generation/integration_generators/tasks.py +1 -1
  456. django_cfg/core/generation/integration_generators/third_party.py +1 -1
  457. django_cfg/core/generation/orchestrator.py +1 -1
  458. django_cfg/core/generation/protocols.py +1 -1
  459. django_cfg/core/generation/utility_generators/__init__.py +1 -1
  460. django_cfg/core/generation/utility_generators/email.py +1 -1
  461. django_cfg/core/generation/utility_generators/i18n.py +1 -1
  462. django_cfg/core/generation/utility_generators/limits.py +1 -1
  463. django_cfg/core/generation/utility_generators/logging.py +1 -1
  464. django_cfg/core/generation/utility_generators/security.py +1 -1
  465. django_cfg/core/generation/utils/helpers.py +1 -1
  466. django_cfg/core/integration/__init__.py +5 -5
  467. django_cfg/core/integration/commands_collector.py +38 -39
  468. django_cfg/core/integration/display/__init__.py +2 -2
  469. django_cfg/core/integration/display/base.py +30 -30
  470. django_cfg/core/integration/display/ngrok.py +35 -36
  471. django_cfg/core/integration/display/startup.py +149 -139
  472. django_cfg/core/integration/url_integration.py +10 -10
  473. django_cfg/core/integration/version_checker.py +20 -19
  474. django_cfg/core/services/config_service.py +4 -4
  475. django_cfg/core/state/__init__.py +1 -1
  476. django_cfg/core/state/registry.py +1 -1
  477. django_cfg/core/types/__init__.py +8 -1
  478. django_cfg/core/validation.py +36 -39
  479. django_cfg/management/commands/check_endpoints.py +3 -1
  480. django_cfg/management/commands/check_settings.py +3 -1
  481. django_cfg/management/commands/clear_constance.py +3 -1
  482. django_cfg/management/commands/create_token.py +3 -1
  483. django_cfg/management/commands/generate_clients.py +3 -1
  484. django_cfg/management/commands/migrate_all.py +3 -1
  485. django_cfg/management/commands/rundramatiq.py +3 -1
  486. django_cfg/management/commands/rundramatiq_simulator.py +3 -1
  487. django_cfg/management/commands/runserver_ngrok.py +3 -1
  488. django_cfg/management/commands/show_config.py +3 -1
  489. django_cfg/management/commands/superuser.py +3 -1
  490. django_cfg/management/commands/task_clear.py +3 -1
  491. django_cfg/management/commands/task_status.py +3 -1
  492. django_cfg/management/commands/test_email.py +3 -1
  493. django_cfg/management/commands/test_telegram.py +3 -1
  494. django_cfg/management/commands/test_twilio.py +3 -1
  495. django_cfg/management/commands/validate_openapi.py +3 -1
  496. django_cfg/middleware/pagination.py +8 -8
  497. django_cfg/middleware/public_endpoints.py +24 -23
  498. django_cfg/middleware/user_activity.py +27 -25
  499. django_cfg/models/__init__.py +19 -20
  500. django_cfg/models/api/__init__.py +4 -4
  501. django_cfg/models/api/config.py +23 -21
  502. django_cfg/models/api/cors.py +17 -16
  503. django_cfg/models/api/drf/__init__.py +1 -1
  504. django_cfg/models/api/drf/config.py +2 -1
  505. django_cfg/models/api/drf/redoc.py +2 -1
  506. django_cfg/models/api/drf/spectacular.py +4 -2
  507. django_cfg/models/api/drf/swagger.py +2 -1
  508. django_cfg/models/api/jwt.py +37 -36
  509. django_cfg/models/api/keys.py +13 -12
  510. django_cfg/models/api/limits.py +31 -30
  511. django_cfg/models/base/config.py +40 -41
  512. django_cfg/models/base/module.py +8 -8
  513. django_cfg/models/django/__init__.py +1 -1
  514. django_cfg/models/django/constance.py +8 -7
  515. django_cfg/models/django/environment.py +5 -3
  516. django_cfg/models/django/openapi.py +6 -16
  517. django_cfg/models/django/revolution_legacy.py +17 -16
  518. django_cfg/models/infrastructure/__init__.py +1 -1
  519. django_cfg/models/infrastructure/cache.py +46 -45
  520. django_cfg/models/infrastructure/database/config.py +4 -6
  521. django_cfg/models/infrastructure/database/converters.py +1 -1
  522. django_cfg/models/infrastructure/database/parsers.py +1 -1
  523. django_cfg/models/infrastructure/database/validators.py +1 -1
  524. django_cfg/models/infrastructure/logging.py +59 -57
  525. django_cfg/models/infrastructure/security.py +26 -24
  526. django_cfg/models/ngrok/auth.py +2 -1
  527. django_cfg/models/ngrok/config.py +3 -2
  528. django_cfg/models/ngrok/tunnel.py +2 -1
  529. django_cfg/models/payments/__init__.py +1 -1
  530. django_cfg/models/payments/api_keys.py +3 -1
  531. django_cfg/models/payments/config.py +4 -1
  532. django_cfg/models/payments/providers/base.py +2 -1
  533. django_cfg/models/payments/providers/nowpayments.py +3 -1
  534. django_cfg/models/services/__init__.py +1 -1
  535. django_cfg/models/services/base.py +2 -1
  536. django_cfg/models/services/email.py +28 -26
  537. django_cfg/models/services/telegram.py +2 -1
  538. django_cfg/models/tasks/__init__.py +2 -2
  539. django_cfg/models/tasks/backends.py +4 -3
  540. django_cfg/models/tasks/config.py +6 -4
  541. django_cfg/models/tasks/utils.py +3 -3
  542. django_cfg/modules/base.py +18 -17
  543. django_cfg/modules/django_admin/__init__.py +14 -15
  544. django_cfg/modules/django_admin/decorators/__init__.py +1 -1
  545. django_cfg/modules/django_admin/decorators/actions.py +8 -7
  546. django_cfg/modules/django_admin/decorators/display.py +9 -7
  547. django_cfg/modules/django_admin/icons/__init__.py +1 -1
  548. django_cfg/modules/django_admin/icons/constants.py +27 -27
  549. django_cfg/modules/django_admin/icons/generate_icons.py +54 -54
  550. django_cfg/modules/django_admin/management/commands/check_endpoints.py +5 -3
  551. django_cfg/modules/django_admin/management/commands/check_settings.py +40 -44
  552. django_cfg/modules/django_admin/management/commands/clear_constance.py +29 -30
  553. django_cfg/modules/django_admin/management/commands/create_token.py +42 -42
  554. django_cfg/modules/django_admin/management/commands/list_urls.py +37 -38
  555. django_cfg/modules/django_admin/management/commands/migrate_all.py +13 -15
  556. django_cfg/modules/django_admin/management/commands/migrator.py +17 -17
  557. django_cfg/modules/django_admin/management/commands/script.py +58 -60
  558. django_cfg/modules/django_admin/management/commands/show_config.py +32 -30
  559. django_cfg/modules/django_admin/management/commands/show_urls.py +46 -44
  560. django_cfg/modules/django_admin/management/commands/superuser.py +47 -48
  561. django_cfg/modules/django_admin/management/commands/tree.py +50 -54
  562. django_cfg/modules/django_admin/mixins/display_mixin.py +16 -15
  563. django_cfg/modules/django_admin/mixins/optimization_mixin.py +9 -8
  564. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +25 -24
  565. django_cfg/modules/django_admin/models/__init__.py +4 -4
  566. django_cfg/modules/django_admin/models/action_models.py +3 -1
  567. django_cfg/modules/django_admin/models/badge_models.py +4 -2
  568. django_cfg/modules/django_admin/models/base.py +3 -3
  569. django_cfg/modules/django_admin/models/display_models.py +1 -0
  570. django_cfg/modules/django_admin/utils/badges.py +27 -26
  571. django_cfg/modules/django_admin/utils/displays.py +49 -49
  572. django_cfg/modules/django_client/apps.py +21 -3
  573. django_cfg/modules/django_client/core/__init__.py +9 -10
  574. django_cfg/modules/django_client/core/archive/manager.py +2 -2
  575. django_cfg/modules/django_client/core/cli/main.py +1 -3
  576. django_cfg/modules/django_client/core/config/config.py +3 -1
  577. django_cfg/modules/django_client/core/config/group.py +1 -0
  578. django_cfg/modules/django_client/core/config/service.py +2 -1
  579. django_cfg/modules/django_client/core/generator/__init__.py +1 -1
  580. django_cfg/modules/django_client/core/generator/base.py +2 -2
  581. django_cfg/modules/django_client/core/generator/python/async_client_gen.py +1 -1
  582. django_cfg/modules/django_client/core/generator/python/files_generator.py +1 -1
  583. django_cfg/modules/django_client/core/generator/python/generator.py +4 -4
  584. django_cfg/modules/django_client/core/generator/python/models_generator.py +1 -1
  585. django_cfg/modules/django_client/core/generator/python/operations_generator.py +2 -2
  586. django_cfg/modules/django_client/core/generator/python/sync_client_gen.py +1 -1
  587. django_cfg/modules/django_client/core/generator/typescript/client_generator.py +3 -1
  588. django_cfg/modules/django_client/core/generator/typescript/fetchers_generator.py +14 -13
  589. django_cfg/modules/django_client/core/generator/typescript/files_generator.py +1 -0
  590. django_cfg/modules/django_client/core/generator/typescript/generator.py +6 -6
  591. django_cfg/modules/django_client/core/generator/typescript/hooks_generator.py +12 -10
  592. django_cfg/modules/django_client/core/generator/typescript/models_generator.py +2 -1
  593. django_cfg/modules/django_client/core/generator/typescript/naming.py +2 -3
  594. django_cfg/modules/django_client/core/generator/typescript/operations_generator.py +12 -10
  595. django_cfg/modules/django_client/core/generator/typescript/schemas_generator.py +3 -2
  596. django_cfg/modules/django_client/core/generator/typescript/templates/client/client.ts.jinja +14 -6
  597. django_cfg/modules/django_client/core/generator/typescript/templates/main_index.ts.jinja +4 -10
  598. django_cfg/modules/django_client/core/groups/__init__.py +1 -1
  599. django_cfg/modules/django_client/core/groups/detector.py +2 -1
  600. django_cfg/modules/django_client/core/groups/manager.py +2 -1
  601. django_cfg/modules/django_client/core/ir/schema.py +1 -1
  602. django_cfg/modules/django_client/core/parser/base.py +0 -2
  603. django_cfg/modules/django_client/core/parser/models/schema.py +1 -1
  604. django_cfg/modules/django_client/core/validation/__init__.py +1 -1
  605. django_cfg/modules/django_client/core/validation/fixer.py +1 -2
  606. django_cfg/modules/django_client/core/validation/reporter.py +2 -2
  607. django_cfg/modules/django_client/core/validation/safety.py +1 -1
  608. django_cfg/modules/django_client/management/commands/generate_client.py +14 -11
  609. django_cfg/modules/django_client/management/commands/validate_openapi.py +4 -6
  610. django_cfg/modules/django_client/spectacular/__init__.py +1 -1
  611. django_cfg/modules/django_client/spectacular/async_detection.py +3 -2
  612. django_cfg/modules/django_client/spectacular/enum_naming.py +1 -1
  613. django_cfg/modules/django_client/spectacular/schema.py +5 -5
  614. django_cfg/modules/django_client/system/__init__.py +24 -0
  615. django_cfg/modules/django_client/system/base_generator.py +123 -0
  616. django_cfg/modules/django_client/system/generate_mjs_clients.py +174 -0
  617. django_cfg/modules/django_client/system/mjs_generator.py +219 -0
  618. django_cfg/modules/django_client/system/schema_parser.py +195 -0
  619. django_cfg/modules/django_client/system/templates/api_client.js.j2 +87 -0
  620. django_cfg/modules/django_client/system/templates/app_index.js.j2 +13 -0
  621. django_cfg/modules/django_client/system/templates/base_client.js.j2 +166 -0
  622. django_cfg/modules/django_client/system/templates/main_index.js.j2 +80 -0
  623. django_cfg/modules/django_client/system/templates/types.js.j2 +24 -0
  624. django_cfg/modules/django_client/urls.py +3 -2
  625. django_cfg/modules/django_currency/__init__.py +17 -18
  626. django_cfg/modules/django_currency/clients/__init__.py +2 -2
  627. django_cfg/modules/django_currency/clients/coinpaprika_client.py +48 -48
  628. django_cfg/modules/django_currency/clients/hybrid_client.py +76 -75
  629. django_cfg/modules/django_currency/core/__init__.py +7 -13
  630. django_cfg/modules/django_currency/core/converter.py +25 -24
  631. django_cfg/modules/django_currency/core/models.py +9 -8
  632. django_cfg/modules/django_currency/database/__init__.py +4 -4
  633. django_cfg/modules/django_currency/database/database_loader.py +65 -66
  634. django_cfg/modules/django_currency/examples/example_database_usage.py +29 -28
  635. django_cfg/modules/django_currency/utils/cache.py +10 -11
  636. django_cfg/modules/django_dashboard/__init__.py +4 -5
  637. django_cfg/modules/django_dashboard/components.py +11 -7
  638. django_cfg/modules/django_dashboard/debug.py +1 -3
  639. django_cfg/modules/django_dashboard/management/commands/debug_dashboard.py +3 -3
  640. django_cfg/modules/django_dashboard/sections/base.py +2 -1
  641. django_cfg/modules/django_dashboard/sections/commands.py +3 -2
  642. django_cfg/modules/django_dashboard/sections/documentation.py +8 -6
  643. django_cfg/modules/django_dashboard/sections/overview.py +13 -9
  644. django_cfg/modules/django_dashboard/sections/stats.py +2 -2
  645. django_cfg/modules/django_dashboard/sections/system.py +2 -1
  646. django_cfg/modules/django_drf_theme/templatetags/tailwind_tags.py +12 -4
  647. django_cfg/modules/django_email/management/commands/test_email.py +8 -7
  648. django_cfg/modules/django_email/service.py +5 -4
  649. django_cfg/modules/django_health/service.py +46 -44
  650. django_cfg/modules/django_import_export/__init__.py +7 -3
  651. django_cfg/modules/django_llm/__init__.py +3 -2
  652. django_cfg/modules/django_llm/example.py +58 -56
  653. django_cfg/modules/django_llm/llm/__init__.py +1 -1
  654. django_cfg/modules/django_llm/llm/cache.py +21 -20
  655. django_cfg/modules/django_llm/llm/client.py +9 -9
  656. django_cfg/modules/django_llm/llm/costs.py +14 -14
  657. django_cfg/modules/django_llm/llm/embeddings/__init__.py +1 -1
  658. django_cfg/modules/django_llm/llm/embeddings/mock_embedder.py +1 -2
  659. django_cfg/modules/django_llm/llm/embeddings/openai_embedder.py +1 -2
  660. django_cfg/modules/django_llm/llm/extractor.py +8 -8
  661. django_cfg/modules/django_llm/llm/models.py +5 -5
  662. django_cfg/modules/django_llm/llm/models_api/models_query.py +2 -2
  663. django_cfg/modules/django_llm/llm/models_cache.py +91 -92
  664. django_cfg/modules/django_llm/llm/providers/config_builder.py +1 -1
  665. django_cfg/modules/django_llm/llm/providers/provider_manager.py +2 -1
  666. django_cfg/modules/django_llm/llm/requests/cache_manager.py +1 -1
  667. django_cfg/modules/django_llm/llm/requests/chat_handler.py +2 -2
  668. django_cfg/modules/django_llm/llm/requests/embedding_handler.py +1 -1
  669. django_cfg/modules/django_llm/llm/responses/response_builder.py +2 -2
  670. django_cfg/modules/django_llm/llm/stats/stats_manager.py +1 -1
  671. django_cfg/modules/django_llm/llm/tokenizer.py +10 -9
  672. django_cfg/modules/django_llm/translator/__init__.py +1 -1
  673. django_cfg/modules/django_llm/translator/cache.py +36 -35
  674. django_cfg/modules/django_llm/translator/detectors/__init__.py +1 -1
  675. django_cfg/modules/django_llm/translator/detectors/script_detector.py +0 -1
  676. django_cfg/modules/django_llm/translator/stats/stats_tracker.py +1 -1
  677. django_cfg/modules/django_llm/translator/translator.py +5 -4
  678. django_cfg/modules/django_llm/translator/translators/__init__.py +1 -1
  679. django_cfg/modules/django_llm/translator/translators/json_translator.py +1 -1
  680. django_cfg/modules/django_llm/translator/utils/__init__.py +1 -1
  681. django_cfg/modules/django_llm/translator/utils/prompt_builder.py +0 -1
  682. django_cfg/modules/django_logging/__init__.py +1 -1
  683. django_cfg/modules/django_logging/django_logger.py +33 -34
  684. django_cfg/modules/django_logging/logger.py +3 -7
  685. django_cfg/modules/django_ngrok/__init__.py +7 -7
  686. django_cfg/modules/django_ngrok/management/commands/runserver_ngrok.py +33 -30
  687. django_cfg/modules/django_ngrok/service.py +33 -32
  688. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +4 -36
  689. django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +1 -1
  690. django_cfg/modules/django_tasks/__init__.py +5 -5
  691. django_cfg/modules/django_tasks/dramatiq_setup.py +1 -1
  692. django_cfg/modules/django_tasks/factory.py +1 -1
  693. django_cfg/modules/django_tasks/management/commands/rundramatiq.py +39 -40
  694. django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +79 -80
  695. django_cfg/modules/django_tasks/management/commands/task_clear.py +34 -34
  696. django_cfg/modules/django_tasks/management/commands/task_status.py +34 -34
  697. django_cfg/modules/django_tasks/service.py +4 -3
  698. django_cfg/modules/django_tasks/settings.py +1 -1
  699. django_cfg/modules/django_telegram/__init__.py +4 -4
  700. django_cfg/modules/django_telegram/management/commands/test_telegram.py +4 -5
  701. django_cfg/modules/django_telegram/service.py +4 -3
  702. django_cfg/modules/django_telegram/utils.py +1 -1
  703. django_cfg/modules/django_twilio/__init__.py +15 -16
  704. django_cfg/modules/django_twilio/_imports.py +1 -1
  705. django_cfg/modules/django_twilio/base.py +9 -5
  706. django_cfg/modules/django_twilio/email_otp.py +4 -3
  707. django_cfg/modules/django_twilio/exceptions.py +36 -36
  708. django_cfg/modules/django_twilio/management/commands/test_twilio.py +6 -7
  709. django_cfg/modules/django_twilio/models.py +54 -53
  710. django_cfg/modules/django_twilio/sendgrid_service.py +70 -72
  711. django_cfg/modules/django_twilio/simple_service.py +42 -41
  712. django_cfg/modules/django_twilio/sms.py +1 -0
  713. django_cfg/modules/django_twilio/twilio_service.py +79 -83
  714. django_cfg/modules/django_twilio/unified.py +6 -5
  715. django_cfg/modules/django_twilio/utils.py +2 -3
  716. django_cfg/modules/django_twilio/whatsapp.py +3 -2
  717. django_cfg/modules/django_unfold/__init__.py +7 -6
  718. django_cfg/modules/django_unfold/callbacks/actions.py +6 -5
  719. django_cfg/modules/django_unfold/callbacks/apizones.py +122 -0
  720. django_cfg/modules/django_unfold/callbacks/base.py +9 -8
  721. django_cfg/modules/django_unfold/callbacks/charts.py +36 -37
  722. django_cfg/modules/django_unfold/callbacks/commands.py +2 -2
  723. django_cfg/modules/django_unfold/callbacks/main.py +27 -27
  724. django_cfg/modules/django_unfold/callbacks/statistics.py +12 -12
  725. django_cfg/modules/django_unfold/callbacks/system.py +5 -5
  726. django_cfg/modules/django_unfold/callbacks/users.py +4 -4
  727. django_cfg/modules/django_unfold/dashboard.py +29 -29
  728. django_cfg/modules/django_unfold/models/__init__.py +23 -8
  729. django_cfg/modules/django_unfold/models/config.py +84 -81
  730. django_cfg/modules/django_unfold/models/dashboard.py +20 -19
  731. django_cfg/modules/django_unfold/models/dropdown.py +6 -4
  732. django_cfg/modules/django_unfold/models/navigation.py +6 -4
  733. django_cfg/modules/django_unfold/models/tabs.py +4 -3
  734. django_cfg/modules/django_unfold/models.py +2 -3
  735. django_cfg/modules/django_unfold/system_monitor.py +27 -25
  736. django_cfg/modules/django_unfold/tailwind.py +12 -14
  737. django_cfg/modules/django_unfold/utils.py +7 -6
  738. django_cfg/pyproject.toml +1 -1
  739. django_cfg/registry/__init__.py +3 -3
  740. django_cfg/registry/core.py +8 -8
  741. django_cfg/registry/modules.py +2 -2
  742. django_cfg/registry/services.py +2 -2
  743. django_cfg/registry/third_party.py +3 -3
  744. django_cfg/routing/__init__.py +3 -3
  745. django_cfg/routing/callbacks.py +27 -26
  746. django_cfg/routing/routers.py +2 -2
  747. django_cfg/static/js/api/accounts/client.mjs +69 -0
  748. django_cfg/static/js/api/accounts/index.mjs +13 -0
  749. django_cfg/static/js/api/base.mjs +166 -0
  750. django_cfg/static/js/api/index.mjs +100 -0
  751. django_cfg/static/js/api/ipc/client.mjs +74 -0
  752. django_cfg/static/js/api/ipc/index.mjs +13 -0
  753. django_cfg/static/js/api/leads/client.mjs +71 -0
  754. django_cfg/static/js/api/leads/index.mjs +13 -0
  755. django_cfg/static/js/api/newsletter/client.mjs +109 -0
  756. django_cfg/static/js/api/newsletter/index.mjs +13 -0
  757. django_cfg/static/js/api/payments/client.mjs +1264 -0
  758. django_cfg/static/js/api/payments/index.mjs +13 -0
  759. django_cfg/static/js/api/support/client.mjs +84 -0
  760. django_cfg/static/js/api/support/index.mjs +13 -0
  761. django_cfg/static/js/api/tasks/client.mjs +74 -0
  762. django_cfg/static/js/api/tasks/index.mjs +13 -0
  763. django_cfg/static/js/api/types.mjs +729 -0
  764. django_cfg/static/js/api-loader.mjs +169 -0
  765. django_cfg/templates/admin/snippets/zones/zones_table.html +4 -3
  766. django_cfg/templatetags/django_cfg.py +4 -4
  767. django_cfg/utils/path_resolution.py +49 -50
  768. django_cfg/utils/smart_defaults.py +27 -29
  769. django_cfg/utils/version_check.py +14 -14
  770. {django_cfg-1.4.20.dist-info → django_cfg-1.4.23.dist-info}/METADATA +1 -1
  771. django_cfg-1.4.23.dist-info/RECORD +1137 -0
  772. django_cfg/apps/payments/static/payments/js/api-client.js +0 -408
  773. django_cfg/modules/django_ipc_client/dashboard/README.md +0 -517
  774. django_cfg/modules/django_ipc_client/dashboard/UNFOLD_INTEGRATION.md +0 -439
  775. django_cfg/modules/django_ipc_client/dashboard/__init__.py +0 -11
  776. django_cfg/modules/django_ipc_client/dashboard/apps.py +0 -22
  777. django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/dashboard.html +0 -200
  778. django_cfg/modules/django_ipc_client/dashboard/urls.py +0 -22
  779. django_cfg/modules/django_ipc_client/dashboard/urls_admin.py +0 -9
  780. django_cfg/modules/django_ipc_client/dashboard/views.py +0 -251
  781. django_cfg/modules/django_rpc_old/POETRY.md +0 -344
  782. django_cfg/modules/django_rpc_old/README.md +0 -397
  783. django_cfg/modules/django_rpc_old/TESTING.md +0 -358
  784. django_cfg/modules/django_rpc_old/__init__.py +0 -39
  785. django_cfg/modules/django_rpc_old/client.py +0 -531
  786. django_cfg/modules/django_rpc_old/config.py +0 -279
  787. django_cfg/modules/django_rpc_old/exceptions.py +0 -172
  788. django_cfg/modules/django_unfold/callbacks/revolution.py +0 -81
  789. django_cfg-1.4.20.dist-info/RECORD +0 -1110
  790. /django_cfg/{modules/django_ipc_client → apps/ipc}/README.md +0 -0
  791. /django_cfg/{modules/django_ipc_client → apps/ipc/services/client}/config.py +0 -0
  792. {django_cfg-1.4.20.dist-info → django_cfg-1.4.23.dist-info}/WHEEL +0 -0
  793. {django_cfg-1.4.20.dist-info → django_cfg-1.4.23.dist-info}/entry_points.txt +0 -0
  794. {django_cfg-1.4.20.dist-info → django_cfg-1.4.23.dist-info}/licenses/LICENSE +0 -0
@@ -10,15 +10,16 @@ All supported currencies are dynamically fetched and cached.
10
10
  """
11
11
 
12
12
  import logging
13
- import requests
14
- import time
15
13
  import random
16
- from datetime import datetime, timedelta
17
- from typing import Dict, Set, Optional, List, Tuple
14
+ import time
15
+ from datetime import datetime
16
+ from typing import Dict, Set
17
+
18
+ import requests
18
19
  from cachetools import TTLCache
19
20
 
20
- from ..core.models import Rate
21
21
  from ..core.exceptions import RateFetchError
22
+ from ..core.models import Rate
22
23
 
23
24
  logger = logging.getLogger(__name__)
24
25
 
@@ -30,7 +31,7 @@ class HybridCurrencyClient:
30
31
  """Initialize hybrid client with multiple data sources."""
31
32
  self._rate_cache = TTLCache(maxsize=1000, ttl=cache_ttl)
32
33
  self._session = requests.Session()
33
-
34
+
34
35
  # User-Agent rotation for better reliability
35
36
  self._user_agents = [
36
37
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
@@ -39,7 +40,7 @@ class HybridCurrencyClient:
39
40
  'curl/7.68.0',
40
41
  'python-requests/2.31.0'
41
42
  ]
42
-
43
+
43
44
  # Data sources configuration (ordered by priority)
44
45
  self._sources = {
45
46
  'fawaz_currency': {
@@ -83,7 +84,7 @@ class HybridCurrencyClient:
83
84
  'get_supported': self._get_cbr_supported_currencies
84
85
  }
85
86
  }
86
-
87
+
87
88
  self._last_request_times = {}
88
89
  self._max_retries = 2
89
90
 
@@ -95,14 +96,14 @@ class HybridCurrencyClient:
95
96
  """Make HTTP request with exponential backoff retry logic."""
96
97
  source_config = self._sources[source]
97
98
  rate_limit = source_config['rate_limit']
98
-
99
+
99
100
  # Rate limiting
100
101
  last_request = self._last_request_times.get(source, 0)
101
102
  time_since_last = time.time() - last_request
102
103
  if time_since_last < rate_limit:
103
104
  sleep_time = rate_limit - time_since_last + random.uniform(0, 0.5)
104
105
  time.sleep(sleep_time)
105
-
106
+
106
107
  for attempt in range(self._max_retries + 1):
107
108
  try:
108
109
  request_headers = {
@@ -112,10 +113,10 @@ class HybridCurrencyClient:
112
113
  }
113
114
  if headers:
114
115
  request_headers.update(headers)
115
-
116
+
116
117
  response = self._session.get(url, headers=request_headers, timeout=10)
117
118
  self._last_request_times[source] = time.time()
118
-
119
+
119
120
  if response.status_code == 429:
120
121
  if attempt < self._max_retries:
121
122
  backoff = (2 ** attempt) * 3 + random.uniform(1, 2)
@@ -124,10 +125,10 @@ class HybridCurrencyClient:
124
125
  continue
125
126
  else:
126
127
  raise requests.exceptions.HTTPError(f"429 Too Many Requests from {source}")
127
-
128
+
128
129
  response.raise_for_status()
129
130
  return response
130
-
131
+
131
132
  except requests.exceptions.RequestException as e:
132
133
  if attempt < self._max_retries:
133
134
  backoff = (2 ** attempt) * 2 + random.uniform(0.5, 1)
@@ -136,7 +137,7 @@ class HybridCurrencyClient:
136
137
  continue
137
138
  else:
138
139
  raise RateFetchError(f"{source} request failed: {e}")
139
-
140
+
140
141
  raise RateFetchError(f"{source}: Failed after {self._max_retries + 1} attempts")
141
142
 
142
143
  # ============================================================================
@@ -146,26 +147,26 @@ class HybridCurrencyClient:
146
147
  def _get_fawaz_supported_currencies(self) -> Set[str]:
147
148
  """Get list of supported currencies from Fawaz API with caching."""
148
149
  cache_key = "fawaz_supported_currencies"
149
-
150
+
150
151
  if cache_key in self._rate_cache:
151
152
  return self._rate_cache[cache_key]
152
-
153
+
153
154
  try:
154
155
  url = f"{self._sources['fawaz_currency']['url']}/usd.json"
155
156
  response = self._make_request_with_retry(url, 'fawaz_currency')
156
157
  data = response.json()
157
-
158
+
158
159
  if 'usd' in data:
159
160
  supported = set(data['usd'].keys())
160
161
  supported.add('usd') # Add USD itself
161
162
  logger.info(f"Fawaz API supports {len(supported)} currencies")
162
-
163
+
163
164
  self._rate_cache[cache_key] = supported
164
165
  return supported
165
166
  else:
166
167
  logger.warning("Fawaz API response format unexpected")
167
168
  return set()
168
-
169
+
169
170
  except Exception as e:
170
171
  logger.warning(f"Failed to get Fawaz supported currencies: {e}")
171
172
  # Minimal fallback
@@ -186,16 +187,16 @@ class HybridCurrencyClient:
186
187
  url = f"{self._sources['fawaz_currency']['url']}/{base_lower}.json"
187
188
  response = self._make_request_with_retry(url, 'fawaz_currency')
188
189
  data = response.json()
189
-
190
+
190
191
  if base_lower not in data:
191
192
  raise RateFetchError(f"Fawaz API doesn't have base currency {base}")
192
-
193
+
193
194
  rates = data[base_lower]
194
195
  quote_lower = quote.lower()
195
-
196
+
196
197
  if quote_lower not in rates:
197
198
  raise RateFetchError(f"Fawaz API doesn't have {base}/{quote} rate")
198
-
199
+
199
200
  return Rate(
200
201
  source="fawaz_currency",
201
202
  base_currency=base.upper(),
@@ -211,30 +212,30 @@ class HybridCurrencyClient:
211
212
  def _get_prebid_supported_currencies(self) -> Set[str]:
212
213
  """Get list of supported currencies from Prebid Currency API with caching."""
213
214
  cache_key = "prebid_supported_currencies"
214
-
215
+
215
216
  if cache_key in self._rate_cache:
216
217
  return self._rate_cache[cache_key]
217
-
218
+
218
219
  try:
219
220
  url = self._sources['prebid_currency']['url']
220
221
  response = self._make_request_with_retry(url, 'prebid_currency')
221
222
  data = response.json()
222
-
223
+
223
224
  if 'conversions' in data:
224
225
  supported = set()
225
226
  # Prebid has conversions from multiple base currencies
226
227
  for base_currency, rates in data['conversions'].items():
227
228
  supported.add(base_currency.upper())
228
229
  supported.update(rate.upper() for rate in rates.keys())
229
-
230
+
230
231
  logger.info(f"Prebid Currency API supports {len(supported)} currencies")
231
-
232
+
232
233
  self._rate_cache[cache_key] = supported
233
234
  return supported
234
235
  else:
235
236
  logger.warning("Prebid Currency API response format unexpected")
236
237
  return set()
237
-
238
+
238
239
  except Exception as e:
239
240
  logger.warning(f"Failed to get Prebid supported currencies: {e}")
240
241
  # Fallback to major currencies
@@ -252,10 +253,10 @@ class HybridCurrencyClient:
252
253
  url = self._sources['prebid_currency']['url']
253
254
  response = self._make_request_with_retry(url, 'prebid_currency')
254
255
  data = response.json()
255
-
256
+
256
257
  base_upper = base.upper()
257
258
  quote_upper = quote.upper()
258
-
259
+
259
260
  # Check if we have direct conversion from base to quote
260
261
  if 'conversions' in data and base_upper in data['conversions']:
261
262
  rates = data['conversions'][base_upper]
@@ -267,7 +268,7 @@ class HybridCurrencyClient:
267
268
  rate=float(rates[quote_upper]),
268
269
  timestamp=datetime.now()
269
270
  )
270
-
271
+
271
272
  # Try reverse conversion (quote to base)
272
273
  if 'conversions' in data and quote_upper in data['conversions']:
273
274
  rates = data['conversions'][quote_upper]
@@ -281,7 +282,7 @@ class HybridCurrencyClient:
281
282
  rate=1.0 / reverse_rate,
282
283
  timestamp=datetime.now()
283
284
  )
284
-
285
+
285
286
  raise RateFetchError(f"Prebid Currency API doesn't have {base}/{quote} rate")
286
287
 
287
288
  # ============================================================================
@@ -291,26 +292,26 @@ class HybridCurrencyClient:
291
292
  def _get_frankfurter_supported_currencies(self) -> Set[str]:
292
293
  """Get list of supported currencies from Frankfurter API with caching."""
293
294
  cache_key = "frankfurter_supported_currencies"
294
-
295
+
295
296
  if cache_key in self._rate_cache:
296
297
  return self._rate_cache[cache_key]
297
-
298
+
298
299
  try:
299
300
  url = f"{self._sources['frankfurter']['url']}"
300
301
  response = self._make_request_with_retry(url, 'frankfurter')
301
302
  data = response.json()
302
-
303
+
303
304
  if 'rates' in data:
304
305
  supported = set(data['rates'].keys())
305
306
  supported.add('EUR') # Add EUR itself (base currency)
306
307
  logger.info(f"Frankfurter API supports {len(supported)} currencies")
307
-
308
+
308
309
  self._rate_cache[cache_key] = supported
309
310
  return supported
310
311
  else:
311
312
  logger.warning("Frankfurter API response format unexpected")
312
313
  return set()
313
-
314
+
314
315
  except Exception as e:
315
316
  logger.warning(f"Failed to get Frankfurter supported currencies: {e}")
316
317
  # Fallback to major fiat currencies
@@ -328,10 +329,10 @@ class HybridCurrencyClient:
328
329
  url = f"{self._sources['frankfurter']['url']}?from={base}&to={quote}"
329
330
  response = self._make_request_with_retry(url, 'frankfurter')
330
331
  data = response.json()
331
-
332
+
332
333
  if 'rates' not in data or quote.upper() not in data['rates']:
333
334
  raise RateFetchError(f"Frankfurter doesn't have {base}/{quote} rate")
334
-
335
+
335
336
  return Rate(
336
337
  source="frankfurter",
337
338
  base_currency=base.upper(),
@@ -347,26 +348,26 @@ class HybridCurrencyClient:
347
348
  def _get_exchangerate_supported_currencies(self) -> Set[str]:
348
349
  """Get list of supported currencies from ExchangeRate-API with caching."""
349
350
  cache_key = "exchangerate_supported_currencies"
350
-
351
+
351
352
  if cache_key in self._rate_cache:
352
353
  return self._rate_cache[cache_key]
353
-
354
+
354
355
  try:
355
356
  url = f"{self._sources['exchangerate_api']['url']}/USD"
356
357
  response = self._make_request_with_retry(url, 'exchangerate_api')
357
358
  data = response.json()
358
-
359
+
359
360
  if data.get('result') == 'success' and 'rates' in data:
360
361
  supported = set(data['rates'].keys())
361
362
  supported.add('USD') # Add USD itself (base currency)
362
363
  logger.info(f"ExchangeRate-API supports {len(supported)} currencies")
363
-
364
+
364
365
  self._rate_cache[cache_key] = supported
365
366
  return supported
366
367
  else:
367
368
  logger.warning("ExchangeRate-API response format unexpected")
368
369
  return set()
369
-
370
+
370
371
  except Exception as e:
371
372
  logger.warning(f"Failed to get ExchangeRate-API supported currencies: {e}")
372
373
  # Fallback to major currencies
@@ -384,14 +385,14 @@ class HybridCurrencyClient:
384
385
  url = f"{self._sources['exchangerate_api']['url']}/{base.upper()}"
385
386
  response = self._make_request_with_retry(url, 'exchangerate_api')
386
387
  data = response.json()
387
-
388
+
388
389
  if data.get('result') != 'success':
389
390
  raise RateFetchError(f"ExchangeRate-API error: {data.get('error-type', 'Unknown error')}")
390
-
391
+
391
392
  rates = data.get('rates', {})
392
393
  if quote.upper() not in rates:
393
394
  raise RateFetchError(f"ExchangeRate-API doesn't have {quote} rate")
394
-
395
+
395
396
  return Rate(
396
397
  source="exchangerate_api",
397
398
  base_currency=base.upper(),
@@ -407,26 +408,26 @@ class HybridCurrencyClient:
407
408
  def _get_cbr_supported_currencies(self) -> Set[str]:
408
409
  """Get list of supported currencies from CBR API with caching."""
409
410
  cache_key = "cbr_supported_currencies"
410
-
411
+
411
412
  if cache_key in self._rate_cache:
412
413
  return self._rate_cache[cache_key]
413
-
414
+
414
415
  try:
415
416
  url = self._sources['cbr']['url']
416
417
  response = self._make_request_with_retry(url, 'cbr')
417
418
  data = response.json()
418
-
419
+
419
420
  if 'Valute' in data:
420
421
  supported = set(data['Valute'].keys())
421
422
  supported.add('RUB') # Add RUB itself
422
423
  logger.info(f"CBR API supports {len(supported)} currencies")
423
-
424
+
424
425
  self._rate_cache[cache_key] = supported
425
426
  return supported
426
427
  else:
427
428
  logger.warning("CBR API response format unexpected")
428
429
  return set()
429
-
430
+
430
431
  except Exception as e:
431
432
  logger.warning(f"Failed to get CBR supported currencies: {e}")
432
433
  # Fallback to major currencies that CBR typically supports
@@ -438,7 +439,7 @@ class HybridCurrencyClient:
438
439
  """CBR supports conversions to/from RUB."""
439
440
  if 'RUB' not in [base.upper(), quote.upper()]:
440
441
  return False
441
-
442
+
442
443
  supported_currencies = self._get_cbr_supported_currencies()
443
444
  return base.upper() in supported_currencies and quote.upper() in supported_currencies
444
445
 
@@ -447,9 +448,9 @@ class HybridCurrencyClient:
447
448
  url = self._sources['cbr']['url']
448
449
  response = self._make_request_with_retry(url, 'cbr')
449
450
  data = response.json()
450
-
451
+
451
452
  base, quote = base.upper(), quote.upper()
452
-
453
+
453
454
  if base == 'RUB' and quote in data.get('Valute', {}):
454
455
  # RUB to other currency
455
456
  currency_data = data['Valute'][quote]
@@ -460,7 +461,7 @@ class HybridCurrencyClient:
460
461
  rate_value = currency_data['Value'] / currency_data['Nominal']
461
462
  else:
462
463
  raise RateFetchError(f"CBR doesn't support {base}/{quote}")
463
-
464
+
464
465
  return Rate(
465
466
  source="cbr",
466
467
  base_currency=base,
@@ -486,56 +487,56 @@ class HybridCurrencyClient:
486
487
  """
487
488
  base, quote = base.upper(), quote.upper()
488
489
  cache_key = f"{base}_{quote}"
489
-
490
+
490
491
  # Check cache first
491
492
  if cache_key in self._rate_cache:
492
493
  logger.debug(f"Retrieved rate {base}/{quote} from cache")
493
494
  return self._rate_cache[cache_key]
494
-
495
+
495
496
  # Try sources in priority order
496
497
  sources_to_try = []
497
498
  for source_name, config in self._sources.items():
498
499
  if config['supports_check'](base, quote):
499
500
  sources_to_try.append((config['priority'], source_name))
500
-
501
+
501
502
  sources_to_try.sort(key=lambda x: x[0]) # Sort by priority
502
-
503
+
503
504
  last_error = None
504
505
  for priority, source_name in sources_to_try:
505
506
  try:
506
507
  logger.debug(f"Trying {source_name} for {base}/{quote}")
507
-
508
+
508
509
  config = self._sources[source_name]
509
510
  rate = config['fetch_method'](base, quote)
510
-
511
+
511
512
  # Cache successful result
512
513
  self._rate_cache[cache_key] = rate
513
514
  logger.info(f"Fetched {base}/{quote} = {rate.rate} from {source_name}")
514
515
  return rate
515
-
516
+
516
517
  except Exception as e:
517
518
  logger.warning(f"{source_name} failed for {base}/{quote}: {e}")
518
519
  last_error = e
519
520
  continue
520
-
521
+
521
522
  raise RateFetchError(f"All sources failed for {base}/{quote}. Last error: {last_error}")
522
523
 
523
524
  def supports_pair(self, base: str, quote: str) -> bool:
524
525
  """Check if any source supports the currency pair."""
525
526
  base, quote = base.upper(), quote.upper()
526
527
  return any(
527
- config['supports_check'](base, quote)
528
+ config['supports_check'](base, quote)
528
529
  for config in self._sources.values()
529
530
  )
530
531
 
531
532
  def get_all_supported_currencies(self) -> Dict[str, str]:
532
533
  """Get all supported currencies across all sources dynamically."""
533
534
  cache_key = "all_supported_currencies"
534
-
535
+
535
536
  # Check cache first
536
537
  if cache_key in self._rate_cache:
537
538
  return self._rate_cache[cache_key]
538
-
539
+
539
540
  # Collect all currencies from all sources
540
541
  all_currencies = set()
541
542
  for source_name, config in self._sources.items():
@@ -545,7 +546,7 @@ class HybridCurrencyClient:
545
546
  logger.debug(f"Added {len(supported)} currencies from {source_name}")
546
547
  except Exception as e:
547
548
  logger.warning(f"Failed to get supported currencies from {source_name}: {e}")
548
-
549
+
549
550
  # Currency names mapping
550
551
  currency_names = {
551
552
  # Major Fiat
@@ -558,7 +559,7 @@ class HybridCurrencyClient:
558
559
  'KRW': 'South Korean Won', 'SGD': 'Singapore Dollar', 'HKD': 'Hong Kong Dollar',
559
560
  'THB': 'Thai Baht', 'MXN': 'Mexican Peso', 'BRL': 'Brazilian Real',
560
561
  'ZAR': 'South African Rand', 'TRY': 'Turkish Lira', 'ILS': 'Israeli Shekel',
561
-
562
+
562
563
  # Cryptocurrencies
563
564
  'BTC': 'Bitcoin', 'ETH': 'Ethereum', 'BNB': 'Binance Coin',
564
565
  'XRP': 'Ripple', 'ADA': 'Cardano', 'SOL': 'Solana',
@@ -566,12 +567,12 @@ class HybridCurrencyClient:
566
567
  'BCH': 'Bitcoin Cash', 'LINK': 'Chainlink', 'UNI': 'Uniswap',
567
568
  'ATOM': 'Cosmos', 'XLM': 'Stellar', 'VET': 'VeChain',
568
569
  'USDT': 'Tether USD', 'USDC': 'USD Coin', 'DAI': 'Dai Stablecoin',
569
-
570
+
570
571
  # Precious Metals
571
572
  'XAU': 'Gold Ounce', 'XAG': 'Silver Ounce',
572
573
  'XPT': 'Platinum Ounce', 'XPD': 'Palladium Ounce'
573
574
  }
574
-
575
+
575
576
  # Create result with proper names
576
577
  result = {}
577
578
  for currency in sorted(all_currencies):
@@ -579,9 +580,9 @@ class HybridCurrencyClient:
579
580
  # Test if currency actually works with USD (basic validation)
580
581
  if self.supports_pair(currency_upper, 'USD'):
581
582
  result[currency_upper] = currency_names.get(currency_upper, f"{currency_upper} Currency")
582
-
583
+
583
584
  # Cache the result
584
585
  self._rate_cache[cache_key] = result
585
586
  logger.info(f"Collected {len(result)} supported currencies from all sources")
586
-
587
+
587
588
  return result
@@ -2,35 +2,29 @@
2
2
  Core currency conversion functionality.
3
3
  """
4
4
 
5
- from .models import (
6
- Rate,
7
- ConversionRequest,
8
- ConversionResult
9
- )
10
-
5
+ from .converter import CurrencyConverter
11
6
  from .exceptions import (
7
+ CacheError,
8
+ ConversionError,
12
9
  CurrencyError,
13
10
  CurrencyNotFoundError,
14
11
  RateFetchError,
15
- ConversionError,
16
- CacheError
17
12
  )
18
-
19
- from .converter import CurrencyConverter
13
+ from .models import ConversionRequest, ConversionResult, Rate
20
14
 
21
15
  __all__ = [
22
16
  # Models
23
17
  'Rate',
24
- 'ConversionRequest',
18
+ 'ConversionRequest',
25
19
  'ConversionResult',
26
-
20
+
27
21
  # Exceptions
28
22
  'CurrencyError',
29
23
  'CurrencyNotFoundError',
30
24
  'RateFetchError',
31
25
  'ConversionError',
32
26
  'CacheError',
33
-
27
+
34
28
  # Main converter
35
29
  'CurrencyConverter'
36
30
  ]
@@ -3,30 +3,31 @@ Main currency converter with intelligent routing.
3
3
  """
4
4
 
5
5
  import logging
6
- from typing import Optional
7
6
 
8
- from .models import Rate, ConversionRequest, ConversionResult
9
- from .exceptions import ConversionError, CurrencyNotFoundError
10
- from ..clients import HybridCurrencyClient, CoinPaprikaClient
11
7
  from ..utils.cache import CacheManager
8
+ from .exceptions import ConversionError, CurrencyNotFoundError
9
+ from .models import ConversionRequest, ConversionResult, Rate
12
10
 
13
11
  logger = logging.getLogger(__name__)
14
12
 
15
13
 
16
14
  class CurrencyConverter:
17
15
  """Main currency converter with provider routing."""
18
-
16
+
19
17
  def __init__(self, cache_ttl: int = 300):
20
18
  """
21
19
  Initialize converter.
22
-
20
+
23
21
  Args:
24
22
  cache_ttl: Cache TTL in seconds
25
23
  """
24
+ # Lazy import to avoid circular dependency
25
+ from ..clients import CoinPaprikaClient, HybridCurrencyClient
26
+
26
27
  self.hybrid = HybridCurrencyClient(cache_ttl=cache_ttl)
27
28
  self.coinpaprika = CoinPaprikaClient(cache_ttl=cache_ttl)
28
29
  self.cache = CacheManager(ttl=cache_ttl)
29
-
30
+
30
31
  def convert(self, amount: float, from_currency: str, to_currency: str) -> ConversionResult:
31
32
  """
32
33
  Convert amount from one currency to another.
@@ -49,7 +50,7 @@ class CurrencyConverter:
49
50
  from_currency=from_currency.upper(),
50
51
  to_currency=to_currency.upper()
51
52
  )
52
-
53
+
53
54
  # Same currency check
54
55
  if request.from_currency == request.to_currency:
55
56
  rate = Rate(
@@ -63,23 +64,23 @@ class CurrencyConverter:
63
64
  result=amount,
64
65
  rate=rate
65
66
  )
66
-
67
+
67
68
  # Get exchange rate
68
69
  rate = self._get_rate(request.from_currency, request.to_currency)
69
-
70
+
70
71
  # Calculate result
71
72
  result = amount * rate.rate
72
-
73
+
73
74
  return ConversionResult(
74
75
  request=request,
75
76
  result=result,
76
77
  rate=rate
77
78
  )
78
-
79
+
79
80
  except Exception as e:
80
81
  logger.error(f"Conversion failed: {e}")
81
82
  raise ConversionError(f"Failed to convert {amount} {from_currency} to {to_currency}: {e}")
82
-
83
+
83
84
  def _get_rate(self, base: str, quote: str) -> Rate:
84
85
  """
85
86
  Get exchange rate using provider routing.
@@ -99,7 +100,7 @@ class CurrencyConverter:
99
100
  cached_rate = self.cache.get_rate(base, quote, source)
100
101
  if cached_rate:
101
102
  return cached_rate
102
-
103
+
103
104
  # Try Hybrid client first (multiple sources with fallback)
104
105
  if self.hybrid.supports_pair(base, quote):
105
106
  try:
@@ -108,7 +109,7 @@ class CurrencyConverter:
108
109
  return rate
109
110
  except Exception as e:
110
111
  logger.warning(f"Hybrid client failed for {base}/{quote}: {e}")
111
-
112
+
112
113
  # Try CoinPaprika next (excellent for crypto, no rate limits)
113
114
  if self.coinpaprika.supports_pair(base, quote):
114
115
  try:
@@ -117,16 +118,16 @@ class CurrencyConverter:
117
118
  return rate
118
119
  except Exception as e:
119
120
  logger.warning(f"CoinPaprika failed for {base}/{quote}: {e}")
120
-
121
+
121
122
  # Try indirect conversion via USD
122
123
  if base != "USD" and quote != "USD":
123
124
  try:
124
125
  return self._indirect_conversion(base, quote)
125
126
  except Exception as e:
126
127
  logger.warning(f"Indirect conversion failed for {base}/{quote}: {e}")
127
-
128
+
128
129
  raise CurrencyNotFoundError(f"No provider supports {base}/{quote}")
129
-
130
+
130
131
  def _indirect_conversion(self, base: str, quote: str) -> Rate:
131
132
  """
132
133
  Perform indirect conversion via USD.
@@ -139,23 +140,23 @@ class CurrencyConverter:
139
140
  Rate object with combined rate
140
141
  """
141
142
  logger.debug(f"Attempting indirect conversion {base} -> USD -> {quote}")
142
-
143
+
143
144
  # Get base/USD rate
144
145
  base_usd_rate = self._get_rate(base, "USD")
145
-
146
- # Get USD/quote rate
146
+
147
+ # Get USD/quote rate
147
148
  usd_quote_rate = self._get_rate("USD", quote)
148
-
149
+
149
150
  # Calculate combined rate
150
151
  combined_rate = base_usd_rate.rate * usd_quote_rate.rate
151
-
152
+
152
153
  return Rate(
153
154
  source=f"{base_usd_rate.source}+{usd_quote_rate.source}",
154
155
  base_currency=base,
155
156
  quote_currency=quote,
156
157
  rate=combined_rate
157
158
  )
158
-
159
+
159
160
  def get_supported_currencies(self) -> dict:
160
161
  """Get list of supported currencies by provider."""
161
162
  return {