django-cfg 1.3.13__py3-none-any.whl → 1.4.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (446) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/user_admin.py +39 -16
  3. django_cfg/apps/accounts/serializers/profile.py +1 -1
  4. django_cfg/apps/accounts/services/otp_service.py +18 -11
  5. django_cfg/apps/accounts/signals.py +15 -24
  6. django_cfg/apps/accounts/utils/notifications.py +217 -358
  7. django_cfg/apps/accounts/views/otp.py +2 -2
  8. django_cfg/apps/accounts/views/webhook.py +1 -1
  9. django_cfg/apps/agents/core/django_agent.py +1 -1
  10. django_cfg/apps/agents/examples/__init__.py +3 -0
  11. django_cfg/apps/agents/examples/simple_example.py +161 -0
  12. django_cfg/apps/api/commands/views.py +66 -83
  13. django_cfg/apps/api/health/drf_views.py +269 -0
  14. django_cfg/apps/api/health/serializers.py +45 -0
  15. django_cfg/apps/api/health/urls.py +6 -1
  16. django_cfg/apps/knowbase/admin/actions/__init__.py +13 -0
  17. django_cfg/apps/knowbase/admin/actions/visibility_actions.py +56 -0
  18. django_cfg/apps/knowbase/admin/document_admin.py +136 -270
  19. django_cfg/apps/knowbase/admin/helpers/__init__.py +17 -0
  20. django_cfg/apps/knowbase/admin/helpers/configs.py +72 -0
  21. django_cfg/apps/knowbase/admin/helpers/display_helpers.py +156 -0
  22. django_cfg/apps/knowbase/admin/helpers/statistics.py +108 -0
  23. django_cfg/apps/knowbase/config/constance_fields.py +1 -1
  24. django_cfg/apps/knowbase/config/settings.py +2 -2
  25. django_cfg/apps/knowbase/examples/__init__.py +3 -0
  26. django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
  27. django_cfg/apps/knowbase/mixins/__init__.py +19 -2
  28. django_cfg/apps/knowbase/mixins/config/__init__.py +14 -0
  29. django_cfg/apps/knowbase/mixins/config/defaults.py +75 -0
  30. django_cfg/apps/knowbase/mixins/config/meta_config.py +120 -0
  31. django_cfg/apps/knowbase/mixins/creator.py +10 -10
  32. django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +199 -0
  33. django_cfg/apps/knowbase/mixins/external_data_mixin.py +105 -403
  34. django_cfg/apps/knowbase/mixins/generators/__init__.py +16 -0
  35. django_cfg/apps/knowbase/mixins/generators/content_generator.py +218 -0
  36. django_cfg/apps/knowbase/mixins/generators/field_analyzer.py +76 -0
  37. django_cfg/apps/knowbase/mixins/generators/metadata_generator.py +124 -0
  38. django_cfg/apps/knowbase/mixins/service.py +2 -2
  39. django_cfg/apps/knowbase/services/archive/__init__.py +1 -0
  40. django_cfg/apps/knowbase/services/archive/analyzers/__init__.py +17 -0
  41. django_cfg/apps/knowbase/services/archive/analyzers/complexity_analyzer.py +33 -0
  42. django_cfg/apps/knowbase/services/archive/analyzers/purpose_detector.py +36 -0
  43. django_cfg/apps/knowbase/services/archive/analyzers/quality_analyzer.py +39 -0
  44. django_cfg/apps/knowbase/services/archive/analyzers/tag_generator.py +103 -0
  45. django_cfg/apps/knowbase/services/archive/chunking/__init__.py +19 -0
  46. django_cfg/apps/knowbase/services/archive/chunking/base.py +81 -0
  47. django_cfg/apps/knowbase/services/archive/chunking/json_chunker.py +62 -0
  48. django_cfg/apps/knowbase/services/archive/chunking/markdown_chunker.py +107 -0
  49. django_cfg/apps/knowbase/services/archive/chunking/python_chunker.py +248 -0
  50. django_cfg/apps/knowbase/services/archive/chunking/text_chunker.py +70 -0
  51. django_cfg/apps/knowbase/services/archive/chunking_service.py +110 -729
  52. django_cfg/apps/knowbase/services/archive/context/__init__.py +14 -0
  53. django_cfg/apps/knowbase/services/archive/context/builders.py +220 -0
  54. django_cfg/apps/knowbase/services/archive/context/models.py +38 -0
  55. django_cfg/apps/knowbase/services/embedding/models.py +18 -14
  56. django_cfg/apps/knowbase/services/embedding/processors.py +6 -3
  57. django_cfg/apps/knowbase/tasks/document_processing.py +11 -3
  58. django_cfg/apps/leads/tests.py +1 -1
  59. django_cfg/apps/payments/admin/api_keys_admin.py +1 -1
  60. django_cfg/apps/payments/admin/balance_admin.py +1 -1
  61. django_cfg/apps/payments/admin/currencies_admin.py +1 -1
  62. django_cfg/apps/payments/admin/payments_admin.py +1 -1
  63. django_cfg/apps/payments/admin/subscriptions_admin.py +1 -1
  64. django_cfg/apps/payments/admin_interface/templates/payments/base.html +59 -126
  65. django_cfg/apps/payments/admin_interface/views/api/payments.py +1 -1
  66. django_cfg/apps/payments/admin_interface/views/api/stats.py +1 -1
  67. django_cfg/apps/payments/admin_interface/views/api/users.py +1 -1
  68. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +1 -1
  69. django_cfg/apps/payments/admin_interface/views/api/webhook_public.py +1 -1
  70. django_cfg/apps/payments/admin_interface/views/base.py +29 -2
  71. django_cfg/apps/payments/apps.py +1 -1
  72. django_cfg/apps/payments/config/django_cfg_integration.py +2 -2
  73. django_cfg/apps/payments/config/helpers.py +3 -2
  74. django_cfg/apps/payments/management/commands/cleanup_expired_data.py +1 -1
  75. django_cfg/apps/payments/management/commands/currency_stats.py +1 -1
  76. django_cfg/apps/payments/management/commands/manage_currencies.py +1 -1
  77. django_cfg/apps/payments/management/commands/manage_providers.py +1 -1
  78. django_cfg/apps/payments/management/commands/process_pending_payments.py +1 -1
  79. django_cfg/apps/payments/management/commands/test_providers.py +1 -1
  80. django_cfg/apps/payments/middleware/api_access.py +1 -1
  81. django_cfg/apps/payments/middleware/rate_limiting.py +1 -1
  82. django_cfg/apps/payments/middleware/usage_tracking.py +1 -1
  83. django_cfg/apps/payments/models/balance.py +2 -2
  84. django_cfg/apps/payments/models/managers/api_key_managers.py +1 -1
  85. django_cfg/apps/payments/models/managers/balance_managers.py +1 -1
  86. django_cfg/apps/payments/models/managers/currency_managers.py +1 -1
  87. django_cfg/apps/payments/models/managers/payment_managers.py +1 -1
  88. django_cfg/apps/payments/models/managers/subscription_managers.py +1 -1
  89. django_cfg/apps/payments/models/payments.py +2 -2
  90. django_cfg/apps/payments/services/cache_service/__init__.py +1 -1
  91. django_cfg/apps/payments/services/cache_service/simple_cache.py +10 -5
  92. django_cfg/apps/payments/services/core/base.py +1 -1
  93. django_cfg/apps/payments/services/core/currency/__init__.py +13 -0
  94. django_cfg/apps/payments/services/core/currency/currency_converter.py +57 -0
  95. django_cfg/apps/payments/services/core/currency/currency_validator.py +61 -0
  96. django_cfg/apps/payments/services/core/operations/__init__.py +15 -0
  97. django_cfg/apps/payments/services/core/operations/payment_canceller.py +100 -0
  98. django_cfg/apps/payments/services/core/operations/payment_creator.py +196 -0
  99. django_cfg/apps/payments/services/core/operations/status_checker.py +100 -0
  100. django_cfg/apps/payments/services/core/payment_service.py +124 -612
  101. django_cfg/apps/payments/services/core/providers/__init__.py +13 -0
  102. django_cfg/apps/payments/services/core/providers/provider_client.py +132 -0
  103. django_cfg/apps/payments/services/core/providers/status_mapper.py +89 -0
  104. django_cfg/apps/payments/services/core/utils/__init__.py +13 -0
  105. django_cfg/apps/payments/services/core/utils/data_converter.py +48 -0
  106. django_cfg/apps/payments/services/core/utils/statistics_calculator.py +69 -0
  107. django_cfg/apps/payments/services/providers/base.py +1 -1
  108. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +3 -3
  109. django_cfg/apps/payments/services/providers/nowpayments/parsers/__init__.py +9 -0
  110. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/__init__.py +23 -0
  111. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/constants.py +23 -0
  112. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/currency_names.py +244 -0
  113. django_cfg/apps/payments/services/providers/nowpayments/parsers/data/patterns.py +511 -0
  114. django_cfg/apps/payments/services/providers/nowpayments/parsers/parser.py +168 -0
  115. django_cfg/apps/payments/services/providers/nowpayments/provider.py +1 -1
  116. django_cfg/apps/payments/services/providers/nowpayments/sync.py +1 -1
  117. django_cfg/apps/payments/services/providers/registry.py +1 -1
  118. django_cfg/apps/payments/services/providers/sync_service.py +1 -1
  119. django_cfg/apps/payments/signals/__init__.py +1 -1
  120. django_cfg/apps/payments/signals/api_key_signals.py +1 -1
  121. django_cfg/apps/payments/signals/balance_signals.py +1 -1
  122. django_cfg/apps/payments/signals/payment_signals.py +1 -1
  123. django_cfg/apps/payments/signals/subscription_signals.py +1 -1
  124. django_cfg/apps/payments/views/api/api_keys.py +1 -1
  125. django_cfg/apps/payments/views/api/balances.py +1 -1
  126. django_cfg/apps/payments/views/api/base.py +1 -1
  127. django_cfg/apps/payments/views/api/currencies.py +1 -1
  128. django_cfg/apps/payments/views/api/payments.py +1 -1
  129. django_cfg/apps/payments/views/api/subscriptions.py +1 -1
  130. django_cfg/apps/payments/views/api/webhooks.py +1 -1
  131. django_cfg/apps/payments/views/serializers/api_keys.py +1 -1
  132. django_cfg/apps/payments/views/serializers/balances.py +1 -1
  133. django_cfg/apps/payments/views/serializers/currencies.py +1 -1
  134. django_cfg/apps/payments/views/serializers/payments.py +1 -1
  135. django_cfg/apps/payments/views/serializers/subscriptions.py +1 -1
  136. django_cfg/apps/payments/views/serializers/webhooks.py +1 -1
  137. django_cfg/apps/support/admin/support_admin.py +21 -13
  138. django_cfg/apps/support/templates/support/chat/access_denied.html +21 -27
  139. django_cfg/apps/support/templates/support/chat/ticket_chat.html +183 -254
  140. django_cfg/apps/support/utils/support_email_service.py +1 -1
  141. django_cfg/apps/tasks/templates/tasks/layout/base.html +20 -115
  142. django_cfg/apps/tasks/utils/simulator.py +1 -1
  143. django_cfg/apps/tasks/views/dashboard.py +33 -3
  144. django_cfg/apps/urls.py +5 -1
  145. django_cfg/cli/README.md +57 -471
  146. django_cfg/cli/commands/create_project.py +140 -529
  147. django_cfg/cli/main.py +13 -10
  148. django_cfg/core/__init__.py +63 -6
  149. django_cfg/core/base/__init__.py +5 -0
  150. django_cfg/core/base/config_model.py +652 -0
  151. django_cfg/core/builders/__init__.py +11 -0
  152. django_cfg/core/builders/apps_builder.py +258 -0
  153. django_cfg/core/builders/middleware_builder.py +115 -0
  154. django_cfg/core/builders/security_builder.py +96 -0
  155. django_cfg/core/config.py +20 -892
  156. django_cfg/core/constants.py +69 -0
  157. django_cfg/core/environment/__init__.py +9 -0
  158. django_cfg/core/exceptions.py +45 -298
  159. django_cfg/core/generation/__init__.py +51 -0
  160. django_cfg/core/generation/core_generators/__init__.py +0 -0
  161. django_cfg/core/generation/core_generators/settings.py +90 -0
  162. django_cfg/core/generation/core_generators/static.py +82 -0
  163. django_cfg/core/generation/core_generators/templates.py +141 -0
  164. django_cfg/core/generation/data_generators/__init__.py +15 -0
  165. django_cfg/core/generation/data_generators/cache.py +132 -0
  166. django_cfg/core/generation/data_generators/database.py +117 -0
  167. django_cfg/core/generation/generation.py +92 -0
  168. django_cfg/core/generation/integration_generators/__init__.py +21 -0
  169. django_cfg/core/generation/integration_generators/api.py +237 -0
  170. django_cfg/core/generation/integration_generators/sessions.py +65 -0
  171. django_cfg/core/generation/integration_generators/tailwind.py +54 -0
  172. django_cfg/core/generation/integration_generators/tasks.py +92 -0
  173. django_cfg/core/generation/integration_generators/third_party.py +144 -0
  174. django_cfg/core/generation/orchestrator.py +285 -0
  175. django_cfg/core/generation/protocols.py +30 -0
  176. django_cfg/core/generation/security_generators/__init__.py +0 -0
  177. django_cfg/core/generation/utility_generators/__init__.py +24 -0
  178. django_cfg/core/generation/utility_generators/email.py +58 -0
  179. django_cfg/core/generation/utility_generators/i18n.py +66 -0
  180. django_cfg/core/generation/utility_generators/limits.py +58 -0
  181. django_cfg/core/generation/utility_generators/logging.py +66 -0
  182. django_cfg/core/generation/utility_generators/security.py +101 -0
  183. django_cfg/core/generation/utils/__init__.py +0 -0
  184. django_cfg/core/generation/utils/helpers.py +32 -0
  185. django_cfg/core/integration/__init__.py +18 -25
  186. django_cfg/core/integration/display/startup.py +146 -133
  187. django_cfg/core/integration/url_integration.py +13 -2
  188. django_cfg/core/services/__init__.py +5 -0
  189. django_cfg/core/services/config_service.py +121 -0
  190. django_cfg/core/state/__init__.py +9 -0
  191. django_cfg/core/state/registry.py +84 -0
  192. django_cfg/core/types/__init__.py +15 -0
  193. django_cfg/core/types/aliases.py +15 -0
  194. django_cfg/core/types/enums.py +49 -0
  195. django_cfg/dashboard/DEBUG_README.md +105 -0
  196. django_cfg/dashboard/REFACTORING_SUMMARY.md +237 -0
  197. django_cfg/dashboard/__init__.py +24 -0
  198. django_cfg/dashboard/components.py +308 -0
  199. django_cfg/dashboard/debug.py +176 -0
  200. django_cfg/dashboard/management/__init__.py +0 -0
  201. django_cfg/dashboard/management/commands/__init__.py +0 -0
  202. django_cfg/dashboard/management/commands/debug_dashboard.py +109 -0
  203. django_cfg/dashboard/sections/__init__.py +1 -0
  204. django_cfg/dashboard/sections/base.py +128 -0
  205. django_cfg/dashboard/sections/commands.py +32 -0
  206. django_cfg/dashboard/sections/overview.py +394 -0
  207. django_cfg/dashboard/sections/stats.py +48 -0
  208. django_cfg/dashboard/sections/system.py +73 -0
  209. django_cfg/management/commands/check_settings.py +6 -2
  210. django_cfg/management/commands/clear_constance.py +6 -1
  211. django_cfg/management/commands/create_token.py +5 -4
  212. django_cfg/management/commands/generate.py +5 -0
  213. django_cfg/management/commands/list_urls.py +7 -2
  214. django_cfg/management/commands/migrate_all.py +6 -2
  215. django_cfg/management/commands/migrator.py +6 -1
  216. django_cfg/management/commands/rundramatiq.py +6 -1
  217. django_cfg/management/commands/rundramatiq_simulator.py +11 -4
  218. django_cfg/management/commands/runserver_ngrok.py +9 -7
  219. django_cfg/management/commands/script.py +25 -21
  220. django_cfg/management/commands/show_config.py +6 -1
  221. django_cfg/management/commands/show_urls.py +8 -3
  222. django_cfg/management/commands/superuser.py +5 -4
  223. django_cfg/management/commands/task_clear.py +8 -3
  224. django_cfg/management/commands/task_status.py +8 -3
  225. django_cfg/management/commands/test_email.py +6 -1
  226. django_cfg/management/commands/test_telegram.py +6 -1
  227. django_cfg/management/commands/test_twilio.py +6 -1
  228. django_cfg/management/commands/tree.py +7 -4
  229. django_cfg/models/__init__.py +88 -3
  230. django_cfg/models/api/__init__.py +27 -0
  231. django_cfg/models/{api.py → api/config.py} +1 -1
  232. django_cfg/models/api/drf/__init__.py +21 -0
  233. django_cfg/models/api/drf/config.py +101 -0
  234. django_cfg/models/api/drf/redoc.py +31 -0
  235. django_cfg/models/api/drf/spectacular.py +129 -0
  236. django_cfg/models/api/drf/swagger.py +59 -0
  237. django_cfg/models/{api_keys.py → api/keys.py} +16 -6
  238. django_cfg/models/{limits.py → api/limits.py} +0 -1
  239. django_cfg/models/base/__init__.py +14 -0
  240. django_cfg/models/django/__init__.py +16 -0
  241. django_cfg/models/{constance.py → django/constance.py} +1 -1
  242. django_cfg/models/{environment.py → django/environment.py} +1 -1
  243. django_cfg/models/infrastructure/__init__.py +17 -0
  244. django_cfg/models/{cache.py → infrastructure/cache.py} +3 -2
  245. django_cfg/models/infrastructure/database/__init__.py +22 -0
  246. django_cfg/models/infrastructure/database/config.py +265 -0
  247. django_cfg/models/infrastructure/database/converters.py +91 -0
  248. django_cfg/models/infrastructure/database/parsers.py +96 -0
  249. django_cfg/models/infrastructure/database/routing.py +85 -0
  250. django_cfg/models/infrastructure/database/validators.py +170 -0
  251. django_cfg/models/{logging.py → infrastructure/logging.py} +1 -1
  252. django_cfg/models/{security.py → infrastructure/security.py} +2 -2
  253. django_cfg/models/ngrok/__init__.py +11 -0
  254. django_cfg/models/ngrok/auth.py +37 -0
  255. django_cfg/models/ngrok/config.py +77 -0
  256. django_cfg/models/ngrok/tunnel.py +35 -0
  257. django_cfg/models/payments/__init__.py +20 -0
  258. django_cfg/models/payments/api_keys.py +57 -0
  259. django_cfg/models/{payments.py → payments/config.py} +56 -154
  260. django_cfg/models/payments/providers/__init__.py +15 -0
  261. django_cfg/models/payments/providers/base.py +25 -0
  262. django_cfg/models/payments/providers/nowpayments.py +48 -0
  263. django_cfg/models/services/__init__.py +18 -0
  264. django_cfg/models/services/base.py +65 -0
  265. django_cfg/models/{email.py → services/email.py} +1 -1
  266. django_cfg/models/services/telegram.py +172 -0
  267. django_cfg/models/tasks/__init__.py +51 -0
  268. django_cfg/models/tasks/backends.py +250 -0
  269. django_cfg/models/tasks/config.py +314 -0
  270. django_cfg/models/tasks/utils.py +174 -0
  271. django_cfg/modules/base.py +18 -3
  272. django_cfg/modules/django_admin/decorators/actions.py +1 -1
  273. django_cfg/modules/django_admin/decorators/display.py +1 -1
  274. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +1 -1
  275. django_cfg/modules/django_currency/examples/__init__.py +3 -0
  276. django_cfg/modules/django_currency/examples/example_database_usage.py +144 -0
  277. django_cfg/modules/django_drf_theme/CHANGELOG.md +210 -0
  278. django_cfg/modules/django_drf_theme/EXAMPLE.md +465 -0
  279. django_cfg/modules/django_drf_theme/IMPLEMENTATION.md +232 -0
  280. django_cfg/modules/django_drf_theme/README.md +207 -0
  281. django_cfg/modules/django_drf_theme/TAILWIND_CDN_GUIDE.md +274 -0
  282. django_cfg/modules/django_drf_theme/__init__.py +23 -0
  283. django_cfg/modules/django_drf_theme/apps.py +15 -0
  284. django_cfg/modules/django_drf_theme/renderers.py +58 -0
  285. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/api.html +375 -0
  286. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/base.html +938 -0
  287. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/filter_form.html +132 -0
  288. django_cfg/modules/django_drf_theme/templates/rest_framework/tailwind/forms/raw_data_form.html +123 -0
  289. django_cfg/modules/django_drf_theme/templatetags/__init__.py +1 -0
  290. django_cfg/modules/django_drf_theme/templatetags/tailwind_tags.py +57 -0
  291. django_cfg/modules/django_email/__init__.py +14 -0
  292. django_cfg/modules/{django_email.py → django_email/service.py} +78 -113
  293. django_cfg/modules/django_email/utils.py +40 -0
  294. django_cfg/modules/django_health/__init__.py +9 -0
  295. django_cfg/modules/{django_health.py → django_health/service.py} +23 -21
  296. django_cfg/modules/django_ipc_client/README.md +346 -0
  297. django_cfg/modules/django_ipc_client/__init__.py +51 -0
  298. django_cfg/modules/django_ipc_client/client.py +540 -0
  299. django_cfg/modules/django_ipc_client/config.py +207 -0
  300. django_cfg/modules/django_ipc_client/dashboard/README.md +517 -0
  301. django_cfg/modules/django_ipc_client/dashboard/UNFOLD_INTEGRATION.md +439 -0
  302. django_cfg/modules/django_ipc_client/dashboard/__init__.py +11 -0
  303. django_cfg/modules/django_ipc_client/dashboard/apps.py +22 -0
  304. django_cfg/modules/django_ipc_client/dashboard/monitor.py +435 -0
  305. django_cfg/modules/django_ipc_client/dashboard/static/django_ipc_dashboard/js/dashboard.js +373 -0
  306. django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/base.html +76 -0
  307. django_cfg/modules/django_ipc_client/dashboard/templates/django_ipc_dashboard/dashboard.html +200 -0
  308. django_cfg/modules/django_ipc_client/dashboard/urls.py +22 -0
  309. django_cfg/modules/django_ipc_client/dashboard/urls_admin.py +9 -0
  310. django_cfg/modules/django_ipc_client/dashboard/views.py +251 -0
  311. django_cfg/modules/django_ipc_client/exceptions.py +201 -0
  312. django_cfg/modules/django_llm/llm/client.py +155 -550
  313. django_cfg/modules/django_llm/llm/embeddings/__init__.py +13 -0
  314. django_cfg/modules/django_llm/llm/embeddings/mock_embedder.py +106 -0
  315. django_cfg/modules/django_llm/llm/embeddings/openai_embedder.py +79 -0
  316. django_cfg/modules/django_llm/llm/models_api/__init__.py +9 -0
  317. django_cfg/modules/django_llm/llm/models_api/models_query.py +163 -0
  318. django_cfg/modules/django_llm/llm/providers/__init__.py +15 -0
  319. django_cfg/modules/django_llm/llm/providers/config_builder.py +103 -0
  320. django_cfg/modules/django_llm/llm/providers/provider_manager.py +148 -0
  321. django_cfg/modules/django_llm/llm/providers/provider_selector.py +60 -0
  322. django_cfg/modules/django_llm/llm/requests/__init__.py +15 -0
  323. django_cfg/modules/django_llm/llm/requests/cache_manager.py +170 -0
  324. django_cfg/modules/django_llm/llm/requests/chat_handler.py +199 -0
  325. django_cfg/modules/django_llm/llm/requests/embedding_handler.py +113 -0
  326. django_cfg/modules/django_llm/llm/responses/__init__.py +9 -0
  327. django_cfg/modules/django_llm/llm/responses/response_builder.py +131 -0
  328. django_cfg/modules/django_llm/llm/stats/__init__.py +9 -0
  329. django_cfg/modules/django_llm/llm/stats/stats_manager.py +107 -0
  330. django_cfg/modules/django_llm/translator/detectors/__init__.py +13 -0
  331. django_cfg/modules/django_llm/translator/detectors/language_detector.py +90 -0
  332. django_cfg/modules/django_llm/translator/detectors/script_detector.py +153 -0
  333. django_cfg/modules/django_llm/translator/stats/__init__.py +11 -0
  334. django_cfg/modules/django_llm/translator/stats/stats_tracker.py +85 -0
  335. django_cfg/modules/django_llm/translator/translator.py +150 -603
  336. django_cfg/modules/django_llm/translator/translators/__init__.py +15 -0
  337. django_cfg/modules/django_llm/translator/translators/json_translator.py +316 -0
  338. django_cfg/modules/django_llm/translator/translators/text_translator.py +139 -0
  339. django_cfg/modules/django_llm/translator/utils/__init__.py +13 -0
  340. django_cfg/modules/django_llm/translator/utils/prompt_builder.py +110 -0
  341. django_cfg/modules/django_llm/translator/utils/text_utils.py +114 -0
  342. django_cfg/modules/django_logging/FIXES_SUMMARY.md +276 -0
  343. django_cfg/modules/django_logging/LOGGING_GUIDE.md +504 -0
  344. django_cfg/modules/django_logging/__init__.py +14 -0
  345. django_cfg/modules/{django_logger.py → django_logging/django_logger.py} +13 -13
  346. django_cfg/modules/{logger.py → django_logging/logger.py} +14 -4
  347. django_cfg/modules/django_ngrok/__init__.py +39 -0
  348. django_cfg/modules/{django_ngrok.py → django_ngrok/service.py} +14 -42
  349. django_cfg/modules/django_rpc_old/POETRY.md +344 -0
  350. django_cfg/modules/django_rpc_old/README.md +397 -0
  351. django_cfg/modules/django_rpc_old/TESTING.md +358 -0
  352. django_cfg/modules/django_rpc_old/__init__.py +39 -0
  353. django_cfg/modules/django_rpc_old/client.py +531 -0
  354. django_cfg/modules/django_rpc_old/config.py +279 -0
  355. django_cfg/modules/django_rpc_old/exceptions.py +172 -0
  356. django_cfg/modules/django_tailwind/README.md +478 -0
  357. django_cfg/modules/django_tailwind/__init__.py +7 -0
  358. django_cfg/modules/django_tailwind/apps.py +10 -0
  359. django_cfg/modules/django_tailwind/templates/django_tailwind/app.html +5 -0
  360. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +117 -0
  361. django_cfg/modules/django_tailwind/templates/django_tailwind/components/navbar.html +124 -0
  362. django_cfg/modules/django_tailwind/templates/django_tailwind/components/theme_toggle.html +54 -0
  363. django_cfg/modules/django_tailwind/templates/django_tailwind/components/user_menu.html +116 -0
  364. django_cfg/modules/django_tailwind/templates/django_tailwind/simple.html +46 -0
  365. django_cfg/modules/django_tailwind/templatetags/__init__.py +1 -0
  366. django_cfg/modules/django_tailwind/templatetags/tailwind_info.py +185 -0
  367. django_cfg/modules/django_tasks/__init__.py +29 -0
  368. django_cfg/modules/django_tasks/factory.py +127 -0
  369. django_cfg/modules/{django_tasks.py → django_tasks/service.py} +45 -274
  370. django_cfg/modules/django_tasks/settings.py +107 -0
  371. django_cfg/modules/django_telegram/__init__.py +29 -0
  372. django_cfg/modules/{django_telegram.py → django_telegram/service.py} +45 -113
  373. django_cfg/modules/django_telegram/utils.py +62 -0
  374. django_cfg/modules/django_twilio/__init__.py +54 -107
  375. django_cfg/modules/django_twilio/_imports.py +30 -0
  376. django_cfg/modules/django_twilio/base.py +192 -0
  377. django_cfg/modules/django_twilio/email_otp.py +227 -0
  378. django_cfg/modules/django_twilio/sendgrid_service.py +1 -1
  379. django_cfg/modules/django_twilio/simple_service.py +1 -2
  380. django_cfg/modules/django_twilio/sms.py +94 -0
  381. django_cfg/modules/django_twilio/twilio_service.py +2 -3
  382. django_cfg/modules/django_twilio/unified.py +310 -0
  383. django_cfg/modules/django_twilio/utils.py +190 -0
  384. django_cfg/modules/django_twilio/whatsapp.py +137 -0
  385. django_cfg/modules/django_unfold/callbacks/base.py +198 -7
  386. django_cfg/modules/django_unfold/callbacks/main.py +102 -10
  387. django_cfg/modules/django_unfold/dashboard.py +65 -43
  388. django_cfg/modules/django_unfold/models/config.py +13 -12
  389. django_cfg/modules/django_unfold/models/navigation.py +8 -3
  390. django_cfg/modules/django_unfold/models/tabs.py +2 -2
  391. django_cfg/modules/django_unfold/templates/unfold/helpers/app_list.html +102 -0
  392. django_cfg/registry/core.py +24 -26
  393. django_cfg/registry/modules.py +5 -2
  394. django_cfg/registry/services.py +20 -3
  395. django_cfg/registry/third_party.py +8 -8
  396. django_cfg/static/admin/css/dashboard.css +260 -0
  397. django_cfg/static/admin/js/commands.js +171 -0
  398. django_cfg/static/admin/js/dashboard.js +126 -0
  399. django_cfg/templates/admin/components/management_commands.js +375 -0
  400. django_cfg/templates/admin/components/progress_bar.html +18 -23
  401. django_cfg/templates/admin/examples/component_class_example.html +156 -0
  402. django_cfg/templates/admin/index.html +48 -20
  403. django_cfg/templates/admin/index_new.html +106 -0
  404. django_cfg/templates/admin/layouts/base_dashboard.html +60 -0
  405. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +1 -20
  406. django_cfg/templates/admin/sections/commands_section.html +626 -0
  407. django_cfg/templates/admin/sections/overview_section.html +112 -0
  408. django_cfg/templates/admin/sections/stats_section.html +35 -0
  409. django_cfg/templates/admin/sections/system_section.html +99 -0
  410. django_cfg/templates/admin/snippets/components/CHARTS_GUIDE.md +322 -0
  411. django_cfg/templates/admin/snippets/components/activity_tracker.html +85 -47
  412. django_cfg/templates/admin/snippets/components/charts_section.html +154 -64
  413. django_cfg/templates/admin/snippets/components/django_commands.html +3 -3
  414. django_cfg/templates/admin/snippets/components/recent_activity_improved.html +25 -0
  415. django_cfg/templates/admin/snippets/components/recent_users_table.html +1 -1
  416. django_cfg/templates/admin/snippets/components/system_metrics.html +179 -93
  417. django_cfg/templates/admin/snippets/zones/zones_table.html +2 -2
  418. django_cfg/templatetags/django_cfg.py +7 -1
  419. django_cfg/utils/smart_defaults.py +4 -4
  420. django_cfg-1.4.3.dist-info/METADATA +533 -0
  421. {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/RECORD +432 -195
  422. django_cfg/apps/accounts/utils/auth_email_service.py +0 -84
  423. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +0 -879
  424. django_cfg/core/generation.py +0 -621
  425. django_cfg/management/commands/validate_config.py +0 -189
  426. django_cfg/models/database.py +0 -480
  427. django_cfg/models/drf.py +0 -272
  428. django_cfg/models/ngrok.py +0 -122
  429. django_cfg/models/services.py +0 -440
  430. django_cfg/models/tasks.py +0 -550
  431. django_cfg/modules/django_twilio/service.py +0 -942
  432. django_cfg/template_archive/django_sample.zip +0 -0
  433. django_cfg/templates/rest_framework/api.html +0 -12
  434. django_cfg/utils/toolkit.py +0 -703
  435. django_cfg-1.3.13.dist-info/METADATA +0 -1029
  436. /django_cfg/apps/accounts/management/commands/{test_otp.py → otp_test.py} +0 -0
  437. /django_cfg/core/{environment.py → environment/detector.py} +0 -0
  438. /django_cfg/models/{cors.py → api/cors.py} +0 -0
  439. /django_cfg/models/{jwt.py → api/jwt.py} +0 -0
  440. /django_cfg/models/{base.py → base/config.py} +0 -0
  441. /django_cfg/models/{cfg.py → base/module.py} +0 -0
  442. /django_cfg/models/{revolution.py → django/revolution.py} +0 -0
  443. /django_cfg/modules/{dramatiq_setup.py → django_tasks/dramatiq_setup.py} +0 -0
  444. {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/WHEEL +0 -0
  445. {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/entry_points.txt +0 -0
  446. {django_cfg-1.3.13.dist-info → django_cfg-1.4.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,47 +1,81 @@
1
1
  """
2
- Payment service for the Universal Payment System v2.0.
2
+ Payment service orchestrator for the Universal Payment System v2.0.
3
3
 
4
- Handles payment creation, status checking, and lifecycle management.
4
+ Coordinates payment operations using specialized components.
5
5
  """
6
6
 
7
- from typing import Optional, Dict, Any
8
- from decimal import Decimal
7
+ from typing import Optional
9
8
  from django.contrib.auth import get_user_model
10
- from django.db import models
11
- from django.utils import timezone
12
9
 
13
- from django_cfg.modules.django_currency import convert_currency, get_exchange_rate
14
10
  from .base import BaseService
15
11
  from ..types import (
16
12
  PaymentCreateRequest, PaymentStatusRequest, PaymentResult,
17
- PaymentData, ServiceOperationResult
13
+ ServiceOperationResult
18
14
  )
19
- from ...models.managers.payment_managers import PaymentStatusUpdateFields
20
- from ...models import UniversalPayment, Currency, ProviderCurrency
21
- from ..providers import ProviderRegistry, get_provider_registry
15
+ from ...models import UniversalPayment
16
+ from ..providers import get_provider_registry
17
+
18
+ # Import specialized components
19
+ from .currency import CurrencyValidator, CurrencyConverter
20
+ from .providers import ProviderClient, StatusMapper
21
+ from .utils import DataConverter, StatisticsCalculator
22
+ from .operations import PaymentCreator, PaymentCanceller, StatusChecker
22
23
 
23
24
  User = get_user_model()
24
25
 
26
+
25
27
  class PaymentService(BaseService):
26
28
  """
27
- Payment service with business logic and validation.
28
-
29
- Handles payment operations using Pydantic validation and Django ORM managers.
29
+ Payment service orchestrator.
30
+
31
+ Coordinates payment operations using specialized components.
32
+ Delegates to:
33
+ - PaymentCreator: Payment creation logic
34
+ - StatusChecker: Status checking and retrieval
35
+ - PaymentCanceller: Payment cancellation
36
+ - CurrencyValidator/Converter: Currency operations
37
+ - ProviderClient: Provider communication
38
+ - DataConverter: Data transformations
39
+ - StatisticsCalculator: Statistics and metrics
30
40
  """
31
-
41
+
32
42
  def __init__(self):
33
- """Initialize payment service with configuration."""
43
+ """Initialize service with components."""
34
44
  super().__init__()
35
- # Direct Constance access instead of ConfigService
45
+
46
+ # Initialize provider registry
36
47
  self.provider_registry = get_provider_registry()
37
-
48
+
49
+ # Initialize currency components
50
+ self.currency_validator = CurrencyValidator(self)
51
+ self.currency_converter = CurrencyConverter(self)
52
+
53
+ # Initialize provider components
54
+ self.provider_client = ProviderClient(self.provider_registry, self)
55
+ self.status_mapper = StatusMapper()
56
+
57
+ # Initialize utilities
58
+ self.data_converter = DataConverter()
59
+ self.stats_calculator = StatisticsCalculator(self)
60
+
61
+ # Initialize operations
62
+ self.payment_creator = PaymentCreator(
63
+ self.provider_registry,
64
+ self.currency_validator,
65
+ self
66
+ )
67
+ self.payment_canceller = PaymentCanceller(self)
68
+ self.status_checker = StatusChecker(self.provider_client, self)
69
+
38
70
  def create_payment(self, request: PaymentCreateRequest) -> PaymentResult:
39
71
  """
40
- Create new payment with full validation.
41
-
72
+ Create new payment.
73
+
74
+ Delegates to PaymentCreator.
75
+
42
76
  Args:
43
77
  request: Payment creation request with validation
44
-
78
+
45
79
  Returns:
46
80
  PaymentResult: Result with payment data or error
47
81
  """
@@ -49,8 +83,7 @@ class PaymentService(BaseService):
49
83
  # Validate request
50
84
  if isinstance(request, dict):
51
85
  request = PaymentCreateRequest(**request)
52
-
53
-
86
+
54
87
  # Get user
55
88
  try:
56
89
  user = User.objects.get(id=request.user_id)
@@ -60,463 +93,80 @@ class PaymentService(BaseService):
60
93
  message=f"User {request.user_id} not found",
61
94
  error_code="user_not_found"
62
95
  )
63
-
64
- # Validate currency
65
- currency_result = self._validate_currency(request.currency_code)
66
- if not currency_result.success:
67
- return PaymentResult(
68
- success=False,
69
- message=currency_result.message,
70
- error_code=currency_result.error_code
71
- )
72
-
73
- # Get provider for payment creation
74
- provider = self.provider_registry.get_provider(request.provider)
75
- if not provider:
76
- return PaymentResult(
77
- success=False,
78
- message=f"Provider {request.provider} not available",
79
- error_code="provider_not_available"
80
- )
81
-
82
- # Create payment in database first
83
- def create_payment_transaction():
84
- currency = currency_result.data['currency']
85
- payment = UniversalPayment.objects.create(
86
- user=user,
87
- amount_usd=request.amount_usd,
88
- currency=currency,
89
- network=currency.native_networks.first(), # Use first native network
90
- provider=request.provider,
91
- status=UniversalPayment.PaymentStatus.PENDING,
92
- status_changed_at=timezone.now(), # Track initial status setting
93
- callback_url=request.callback_url,
94
- cancel_url=request.cancel_url,
95
- description=request.description,
96
- expires_at=timezone.now() + timezone.timedelta(hours=1) # 1 hour expiry
97
- )
98
- return payment
99
-
100
- payment = self._execute_with_transaction(create_payment_transaction)
101
-
102
-
103
- # Create payment with provider
104
- from ..providers.models import PaymentRequest as ProviderPaymentRequest
105
-
106
- # Use provider_currency_code from metadata if available, otherwise use original currency_code
107
- provider_currency_code = request.metadata.get('provider_currency_code', request.currency_code)
108
-
109
- provider_request = ProviderPaymentRequest(
110
- amount_usd=request.amount_usd,
111
- currency_code=provider_currency_code, # Use provider-specific currency code
112
- order_id=str(payment.id),
113
- callback_url=request.callback_url,
114
- cancel_url=request.cancel_url,
115
- description=request.description,
116
- metadata=request.metadata
117
- )
118
-
119
- provider_response = provider.create_payment(provider_request)
120
-
121
-
122
- # Update payment with provider response
123
- if provider_response.success:
124
- def update_payment_transaction():
125
- payment.provider_payment_id = provider_response.provider_payment_id
126
- payment.pay_amount = provider_response.amount # Fix: use pay_amount instead of crypto_amount
127
- payment.payment_url = provider_response.payment_url
128
- payment.qr_code_url = provider_response.qr_code_url
129
- payment.pay_address = provider_response.wallet_address # Fix: use pay_address instead of wallet_address
130
- if provider_response.expires_at:
131
- payment.expires_at = provider_response.expires_at
132
- payment.save()
133
- return payment
134
-
135
- payment = self._execute_with_transaction(update_payment_transaction)
136
-
137
- # Convert to PaymentData using our helper method
138
- payment_data = self._convert_payment_to_data(payment)
139
-
140
- self._log_operation(
141
- "create_payment",
142
- True,
143
- payment_id=str(payment.id),
144
- user_id=request.user_id,
145
- amount_usd=request.amount_usd
146
- )
147
-
148
- return PaymentResult(
149
- success=True,
150
- message="Payment created successfully",
151
- payment_id=str(payment.id),
152
- status=payment.status,
153
- amount_usd=payment.amount_usd,
154
- crypto_amount=payment.pay_amount,
155
- currency_code=payment.currency.code,
156
- payment_url=payment.payment_url,
157
- expires_at=payment.expires_at,
158
- data={'payment': payment_data.model_dump()}
159
- )
160
-
161
- else:
162
- # Mark payment as failed if provider creation failed
163
- self.logger.error("❌ PAYMENT SERVICE: Provider creation failed", extra={
164
- 'payment_id': str(payment.id),
165
- 'provider_error': getattr(provider_response, 'error_message', 'Unknown error')
166
- })
167
- payment.mark_failed(
168
- reason=provider_response.error_message,
169
- error_code="provider_creation_failed"
170
- )
171
-
172
- # Return error result when provider fails
173
- self._log_operation(
174
- "create_payment",
175
- False,
176
- payment_id=str(payment.id),
177
- user_id=request.user_id,
178
- amount_usd=request.amount_usd,
179
- error=provider_response.error_message
180
- )
181
-
182
- return PaymentResult(
183
- success=False,
184
- message=provider_response.error_message or "Payment creation failed",
185
- error_code="provider_creation_failed",
186
- payment_id=str(payment.id),
187
- status=payment.status,
188
- data={'error_details': getattr(provider_response, 'raw_response', {})}
189
- )
190
-
96
+
97
+ # Delegate to creator
98
+ return self.payment_creator.create_payment(request, user)
99
+
191
100
  except Exception as e:
192
101
  return PaymentResult(**self._handle_exception(
193
102
  "create_payment", e,
194
103
  user_id=request.user_id if hasattr(request, 'user_id') else None
195
104
  ).model_dump())
196
-
105
+
197
106
  def get_payment_status(self, request: PaymentStatusRequest) -> PaymentResult:
198
107
  """
199
- Get payment status with optional provider check.
200
-
108
+ Get payment status.
109
+
110
+ Delegates to StatusChecker.
111
+
201
112
  Args:
202
113
  request: Payment status request
203
-
114
+
204
115
  Returns:
205
116
  PaymentResult: Current payment status
206
117
  """
207
- try:
208
- # Validate request
209
- if isinstance(request, dict):
210
- request = PaymentStatusRequest(**request)
211
-
212
- self.logger.debug("Getting payment status", extra={
213
- 'payment_id': request.payment_id,
214
- 'force_provider_check': request.force_provider_check
215
- })
216
-
217
- # Get payment
218
- try:
219
- payment = UniversalPayment.objects.get(id=request.payment_id)
220
- except UniversalPayment.DoesNotExist:
221
- return PaymentResult(
222
- success=False,
223
- message=f"Payment {request.payment_id} not found",
224
- error_code="payment_not_found"
225
- )
226
-
227
- # Check user authorization if provided
228
- if request.user_id and payment.user_id != request.user_id:
229
- return PaymentResult(
230
- success=False,
231
- message="Access denied to payment",
232
- error_code="access_denied"
233
- )
234
-
235
- # Force provider check if requested
236
- if request.force_provider_check:
237
- provider_result = self._check_provider_status(payment)
238
- if provider_result.success and provider_result.data.get('status_changed'):
239
- # Reload payment if status was updated
240
- payment.refresh_from_db()
241
-
242
- # Convert to PaymentData using from_attributes
243
- payment_data = self._convert_payment_to_data(payment)
244
-
245
- return PaymentResult(
246
- success=True,
247
- message="Payment status retrieved",
248
- payment_id=str(payment.id),
249
- status=payment.status,
250
- amount_usd=payment.amount_usd,
251
- crypto_amount=payment.pay_amount,
252
- currency_code=payment.currency.code,
253
- provider_payment_id=payment.provider_payment_id,
254
- payment_url=payment.payment_url,
255
- qr_code_url=getattr(payment, 'qr_code_url', None),
256
- wallet_address=payment.pay_address,
257
- expires_at=payment.expires_at,
258
- data={'payment': payment_data.model_dump()}
259
- )
260
-
261
- except Exception as e:
262
- return PaymentResult(**self._handle_exception(
263
- "get_payment_status", e,
264
- payment_id=request.payment_id if hasattr(request, 'payment_id') else None
265
- ).model_dump())
266
-
118
+ return self.status_checker.get_payment_status(request)
119
+
267
120
  def cancel_payment(self, payment_id: str, reason: str = None) -> PaymentResult:
268
121
  """
269
- Cancel payment if possible.
270
-
122
+ Cancel payment.
123
+
124
+ Delegates to PaymentCanceller.
125
+
271
126
  Args:
272
127
  payment_id: Payment ID to cancel
273
128
  reason: Cancellation reason
274
-
129
+
275
130
  Returns:
276
131
  PaymentResult: Cancellation result
277
132
  """
278
- try:
279
- self.logger.info("Cancelling payment", extra={
280
- 'payment_id': payment_id,
281
- 'reason': reason
282
- })
283
-
284
- # Get payment
285
- try:
286
- payment = UniversalPayment.objects.get(id=payment_id)
287
- except UniversalPayment.DoesNotExist:
288
- return PaymentResult(
289
- success=False,
290
- message=f"Payment {payment_id} not found",
291
- error_code="payment_not_found"
292
- )
293
-
294
- # Check if payment can be cancelled
295
- if not payment.can_be_cancelled():
296
- return PaymentResult(
297
- success=False,
298
- message=f"Payment {payment_id} cannot be cancelled (status: {payment.status})",
299
- error_code="cannot_cancel"
300
- )
301
-
302
- # Cancel using manager
303
- def cancel_payment_transaction():
304
- return payment.cancel(reason)
305
-
306
- success = self._execute_with_transaction(cancel_payment_transaction)
307
-
308
- if success:
309
- payment.refresh_from_db()
310
- payment_data = self._convert_payment_to_data(payment)
311
-
312
- self._log_operation(
313
- "cancel_payment",
314
- True,
315
- payment_id=payment_id,
316
- reason=reason
317
- )
318
-
319
- return PaymentResult(
320
- success=True,
321
- message="Payment cancelled successfully",
322
- payment_id=str(payment.id),
323
- status=payment.status,
324
- data={'payment': payment_data.model_dump()}
325
- )
326
- else:
327
- return PaymentResult(
328
- success=False,
329
- message="Failed to cancel payment",
330
- error_code="cancel_failed"
331
- )
332
-
333
- except Exception as e:
334
- return PaymentResult(**self._handle_exception(
335
- "cancel_payment", e,
336
- payment_id=payment_id
337
- ).model_dump())
338
-
339
- def _validate_currency(self, currency_code: str) -> ServiceOperationResult:
340
- """Validate currency is supported."""
341
- try:
342
- currency = Currency.objects.get(code=currency_code, is_active=True)
343
-
344
- # Check if currency is supported by any provider
345
- provider_currency = ProviderCurrency.objects.filter(
346
- currency=currency,
347
- is_enabled=True
348
- ).first()
349
-
350
- if not provider_currency:
351
- return self._create_error_result(
352
- f"Currency {currency_code} not supported by any provider",
353
- "currency_not_supported"
354
- )
355
-
356
- return self._create_success_result(
357
- "Currency is valid",
358
- {'currency': currency} # Wrap in dict for Pydantic
359
- )
360
-
361
- except Currency.DoesNotExist:
362
- return self._create_error_result(
363
- f"Currency {currency_code} not found",
364
- "currency_not_found"
365
- )
366
-
367
- def _convert_usd_to_crypto(self, amount_usd: float, currency_code: str) -> ServiceOperationResult:
368
- """Convert USD amount to cryptocurrency."""
369
- try:
370
- # Use django_currency module for conversion
371
- crypto_amount = convert_currency(amount_usd, 'USD', currency_code)
372
-
373
- return self._create_success_result(
374
- "Currency converted successfully",
375
- {
376
- 'amount_usd': amount_usd,
377
- 'crypto_amount': Decimal(str(crypto_amount)),
378
- 'currency_code': currency_code,
379
- 'exchange_rate': get_exchange_rate('USD', currency_code)
380
- }
381
- )
382
-
383
- except Exception as e:
384
- return self._create_error_result(
385
- f"Currency conversion failed: {e}",
386
- "conversion_failed"
387
- )
388
-
389
- def _check_provider_status(self, payment: UniversalPayment) -> ServiceOperationResult:
390
- """Check payment status with provider and update database if needed."""
391
- try:
392
- if not payment.provider_payment_id:
393
- return self._create_success_result(
394
- "No provider payment ID, skipping provider check",
395
- {'status_changed': False}
396
- )
397
-
398
- # Get provider instance
399
- provider = self.provider_registry.get_provider(payment.provider)
400
- if not provider:
401
- return self._create_error_result(
402
- f"Provider {payment.provider} not available",
403
- "provider_not_available"
404
- )
405
-
406
- # Check status with provider
407
- provider_response = provider.get_payment_status(payment.provider_payment_id)
408
-
409
- if not provider_response.success:
410
- self.logger.warning(f"Provider status check failed for payment {payment.id}", extra={
411
- 'payment_id': str(payment.id),
412
- 'provider_payment_id': payment.provider_payment_id,
413
- 'error': provider_response.error_message
414
- })
415
- return self._create_error_result(
416
- f"Provider status check failed: {provider_response.error_message}",
417
- "provider_check_failed"
418
- )
419
-
420
- # Map provider status to our status
421
- original_status = payment.status
422
- new_status = self._map_provider_status(provider_response.status, payment.provider)
423
-
424
- status_changed = False
425
-
426
- # Update payment if status changed
427
- if new_status and new_status != original_status:
428
- def update_payment_transaction():
429
- nonlocal status_changed
430
-
431
- # Update status
432
- payment.status = new_status
433
- payment.status_changed_at = timezone.now() # Track when status changed
434
-
435
- # Update other fields from provider response
436
- if provider_response.transaction_hash and not payment.transaction_hash:
437
- payment.transaction_hash = provider_response.transaction_hash
438
-
439
- if provider_response.confirmations_count is not None:
440
- payment.confirmations_count = provider_response.confirmations_count
441
-
442
- # Mark as completed if status is completed/confirmed
443
- if new_status in ['completed', 'confirmed'] and not payment.completed_at:
444
- payment.completed_at = timezone.now()
445
-
446
- payment.save()
447
- status_changed = True
448
-
449
- return True
450
-
451
- # Execute in transaction
452
- self._execute_with_transaction(update_payment_transaction)
453
-
454
- self.logger.info(f"Payment status updated from provider", extra={
455
- 'payment_id': str(payment.id),
456
- 'provider_payment_id': payment.provider_payment_id,
457
- 'status_change': f"{original_status} -> {new_status}",
458
- 'provider': payment.provider
459
- })
460
-
461
- return self._create_success_result(
462
- f"Provider status checked: {original_status} -> {new_status}" if status_changed else "No status change",
463
- {
464
- 'status_changed': status_changed,
465
- 'original_status': original_status,
466
- 'new_status': new_status,
467
- 'provider_response': provider_response.raw_response
468
- }
469
- )
470
-
471
- except Exception as e:
472
- self.logger.error(f"Provider status check failed", extra={
473
- 'payment_id': str(payment.id),
474
- 'error': str(e)
475
- })
476
- return self._create_error_result(
477
- f"Provider check failed: {e}",
478
- "provider_check_failed"
479
- )
480
-
481
- def _map_provider_status(self, provider_status: str, provider: str) -> Optional[str]:
482
- """Map provider-specific status to universal status."""
483
- if provider == 'nowpayments':
484
- status_mapping = {
485
- 'waiting': 'pending',
486
- 'confirming': 'confirming',
487
- 'confirmed': 'confirmed',
488
- 'finished': 'completed',
489
- 'failed': 'failed',
490
- 'refunded': 'refunded',
491
- 'expired': 'expired'
492
- }
493
- return status_mapping.get(provider_status.lower())
494
-
495
- # Default mapping for unknown providers
496
- return provider_status.lower() if provider_status else None
497
-
133
+ return self.payment_canceller.cancel_payment(payment_id, reason)
134
+
498
135
  def get_user_payments(
499
- self,
500
- user_id: int,
136
+ self,
137
+ user_id: int,
501
138
  status: Optional[str] = None,
502
139
  limit: int = 50,
503
140
  offset: int = 0
504
141
  ) -> ServiceOperationResult:
505
- """Get user payments with pagination."""
142
+ """
143
+ Get user payments with pagination.
144
+
145
+ Simple query method - kept in main service.
146
+
147
+ Args:
148
+ user_id: User ID
149
+ status: Optional status filter
150
+ limit: Page size
151
+ offset: Page offset
152
+
153
+ Returns:
154
+ ServiceOperationResult with payments list
155
+ """
506
156
  try:
507
157
  queryset = UniversalPayment.objects.filter(user_id=user_id)
508
-
158
+
509
159
  if status:
510
160
  queryset = queryset.filter(status=status)
511
-
161
+
512
162
  total_count = queryset.count()
513
163
  payments = queryset.order_by('-created_at')[offset:offset + limit]
514
-
164
+
515
165
  payment_data = []
516
166
  for payment in payments:
517
- payment_obj = self._convert_payment_to_data(payment)
167
+ payment_obj = self.data_converter.payment_to_data(payment)
518
168
  payment_data.append(payment_obj.model_dump())
519
-
169
+
520
170
  return self._create_success_result(
521
171
  f"Retrieved {len(payment_data)} payments",
522
172
  {
@@ -527,180 +177,42 @@ class PaymentService(BaseService):
527
177
  'has_more': offset + limit < total_count
528
178
  }
529
179
  )
530
-
180
+
531
181
  except Exception as e:
532
182
  return self._handle_exception(
533
183
  "get_user_payments", e,
534
184
  user_id=user_id
535
185
  )
536
-
537
- def _convert_payment_to_data(self, payment: UniversalPayment) -> PaymentData:
538
- """Convert Django UniversalPayment to PaymentData."""
539
- return PaymentData(
540
- id=str(payment.id),
541
- user_id=payment.user_id,
542
- amount_usd=float(payment.amount_usd),
543
- crypto_amount=payment.pay_amount,
544
- currency_code=payment.currency.code,
545
- provider=payment.provider,
546
- status=payment.status,
547
- provider_payment_id=payment.provider_payment_id,
548
- payment_url=payment.payment_url,
549
- qr_code_url=getattr(payment, 'qr_code_url', None),
550
- wallet_address=payment.pay_address,
551
- callback_url=payment.callback_url,
552
- cancel_url=payment.cancel_url,
553
- description=payment.description,
554
- metadata={},
555
- created_at=payment.created_at,
556
- updated_at=payment.updated_at,
557
- expires_at=payment.expires_at,
558
- completed_at=getattr(payment, 'completed_at', None)
559
- )
560
-
186
+
561
187
  def get_payment_stats(self, days: int = 30) -> ServiceOperationResult:
562
- """Get payment statistics."""
563
- try:
564
- from datetime import timedelta
565
-
566
- since = timezone.now() - timedelta(days=days)
567
-
568
- stats = UniversalPayment.objects.filter(
569
- created_at__gte=since
570
- ).aggregate(
571
- total_payments=models.Count('id'),
572
- total_amount_usd=models.Sum('amount_usd'),
573
- completed_payments=models.Count(
574
- 'id',
575
- filter=models.Q(status=UniversalPayment.PaymentStatus.COMPLETED)
576
- ),
577
- failed_payments=models.Count(
578
- 'id',
579
- filter=models.Q(status=UniversalPayment.PaymentStatus.FAILED)
580
- )
581
- )
582
-
583
- # Calculate success rate
584
- total = stats['total_payments'] or 0
585
- completed = stats['completed_payments'] or 0
586
- success_rate = (completed / total * 100) if total > 0 else 0
587
-
588
- stats['success_rate'] = round(success_rate, 2)
589
- stats['period_days'] = days
590
-
591
- return self._create_success_result(
592
- f"Payment statistics for {days} days",
593
- stats
594
- )
595
-
596
- except Exception as e:
597
- return self._handle_exception("get_payment_stats", e)
598
-
599
- def _check_provider_status(self, payment: 'UniversalPayment') -> ServiceOperationResult:
600
188
  """
601
- Check payment status with provider and update if changed.
602
-
189
+ Get payment statistics.
190
+
191
+ Delegates to StatisticsCalculator.
192
+
603
193
  Args:
604
- payment: Payment object to check
605
-
194
+ days: Number of days to analyze
195
+
606
196
  Returns:
607
- ServiceOperationResult: Result with status_changed flag
197
+ ServiceOperationResult with statistics
198
+ """
199
+ return self.stats_calculator.get_payment_stats(days)
200
+
201
+ # Private helper methods for backward compatibility
202
+
203
+ def _get_user(self, user_id: int):
204
+ """
205
+ Get user by ID.
206
+
207
+ Helper method for internal use.
208
+
209
+ Args:
210
+ user_id: User ID
211
+
212
+ Returns:
213
+ User instance or None
608
214
  """
609
215
  try:
610
- from ..providers.registry import ProviderRegistry
611
- from django.db import transaction
612
-
613
- self.logger.debug("Checking provider status", extra={
614
- 'payment_id': str(payment.id),
615
- 'current_status': payment.status,
616
- 'provider': payment.provider
617
- })
618
-
619
- # Get provider instance
620
- registry = ProviderRegistry()
621
- provider = registry.get_provider(payment.provider)
622
-
623
- if not provider:
624
- return self._create_error_result(
625
- f"Provider {payment.provider} not found",
626
- "provider_not_found"
627
- )
628
-
629
- # Get status from provider
630
- provider_response = provider.get_payment_status(payment.provider_payment_id)
631
-
632
- if not provider_response.success:
633
- self.logger.warning("Provider status check failed", extra={
634
- 'payment_id': str(payment.id),
635
- 'provider': payment.provider,
636
- 'error': provider_response.error_message
637
- })
638
- return self._create_error_result(
639
- f"Provider status check failed: {provider_response.error_message}",
640
- "provider_check_failed"
641
- )
642
-
643
- # Map provider status to universal status
644
- provider_status = provider_response.data.get('status', '').lower()
645
- status_mapping = {
646
- 'waiting': UniversalPayment.PaymentStatus.PENDING,
647
- 'confirming': UniversalPayment.PaymentStatus.PENDING,
648
- 'confirmed': UniversalPayment.PaymentStatus.COMPLETED,
649
- 'sending': UniversalPayment.PaymentStatus.PENDING,
650
- 'partially_paid': UniversalPayment.PaymentStatus.PENDING,
651
- 'finished': UniversalPayment.PaymentStatus.COMPLETED,
652
- 'failed': UniversalPayment.PaymentStatus.FAILED,
653
- 'refunded': UniversalPayment.PaymentStatus.FAILED,
654
- 'expired': UniversalPayment.PaymentStatus.EXPIRED,
655
- }
656
-
657
- new_status = status_mapping.get(provider_status, payment.status)
658
- status_changed = new_status != payment.status
659
-
660
- # Update payment if status changed
661
- if status_changed:
662
- with transaction.atomic():
663
- # Prepare extra fields from provider response
664
- provider_data = provider_response.data
665
-
666
- extra_fields = PaymentStatusUpdateFields(
667
- transaction_hash=provider_data.get('transaction_hash'),
668
- confirmations_count=provider_data.get('confirmations_count')
669
- )
670
-
671
- # Use manager method for consistent status updates
672
- from ...models import UniversalPayment
673
- success = UniversalPayment.objects.update_payment_status(
674
- payment, new_status, extra_fields
675
- )
676
-
677
- if not success:
678
- return self._create_error_result(
679
- "Failed to update payment status",
680
- "status_update_failed"
681
- )
682
-
683
- self.logger.info("Payment status updated", extra={
684
- 'payment_id': str(payment.id),
685
- 'old_status': payment.status,
686
- 'new_status': new_status,
687
- 'provider_status': provider_status
688
- })
689
-
690
- return self._create_success_result(
691
- "Provider status checked",
692
- {
693
- 'status_changed': status_changed,
694
- 'old_status': payment.status if not status_changed else None,
695
- 'new_status': new_status,
696
- 'provider_status': provider_status,
697
- 'provider_response': provider_response.data
698
- }
699
- )
700
-
701
- except Exception as e:
702
- self.logger.error("Error checking provider status", extra={
703
- 'payment_id': str(payment.id),
704
- 'error': str(e)
705
- })
706
- return self._handle_exception("_check_provider_status", e)
216
+ return User.objects.get(id=user_id)
217
+ except User.DoesNotExist:
218
+ return None