django-cfg 1.3.7__py3-none-any.whl → 1.3.11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/__init__.py +24 -8
  3. django_cfg/apps/accounts/admin/activity_admin.py +146 -0
  4. django_cfg/apps/accounts/admin/filters.py +98 -22
  5. django_cfg/apps/accounts/admin/group_admin.py +86 -0
  6. django_cfg/apps/accounts/admin/inlines.py +42 -13
  7. django_cfg/apps/accounts/admin/otp_admin.py +115 -0
  8. django_cfg/apps/accounts/admin/registration_admin.py +173 -0
  9. django_cfg/apps/accounts/admin/resources.py +123 -19
  10. django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
  11. django_cfg/apps/accounts/admin/user_admin.py +362 -0
  12. django_cfg/apps/agents/admin/__init__.py +17 -4
  13. django_cfg/apps/agents/admin/execution_admin.py +204 -183
  14. django_cfg/apps/agents/admin/registry_admin.py +230 -255
  15. django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
  16. django_cfg/apps/agents/core/__init__.py +1 -1
  17. django_cfg/apps/agents/core/django_agent.py +221 -0
  18. django_cfg/apps/agents/core/exceptions.py +14 -0
  19. django_cfg/apps/agents/core/orchestrator.py +18 -3
  20. django_cfg/apps/knowbase/admin/__init__.py +1 -1
  21. django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
  22. django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
  23. django_cfg/apps/knowbase/admin/document_admin.py +269 -262
  24. django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
  25. django_cfg/apps/knowbase/config/settings.py +21 -4
  26. django_cfg/apps/knowbase/views/chat_views.py +3 -0
  27. django_cfg/apps/leads/admin/__init__.py +3 -1
  28. django_cfg/apps/leads/admin/leads_admin.py +235 -35
  29. django_cfg/apps/maintenance/admin/__init__.py +2 -2
  30. django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
  31. django_cfg/apps/maintenance/admin/log_admin.py +143 -61
  32. django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
  33. django_cfg/apps/maintenance/admin/site_admin.py +213 -352
  34. django_cfg/apps/newsletter/admin/__init__.py +29 -2
  35. django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
  36. django_cfg/apps/payments/admin/__init__.py +18 -27
  37. django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
  38. django_cfg/apps/payments/admin/balance_admin.py +166 -632
  39. django_cfg/apps/payments/admin/currencies_admin.py +235 -607
  40. django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
  41. django_cfg/apps/payments/admin/filters.py +83 -3
  42. django_cfg/apps/payments/admin/networks_admin.py +269 -0
  43. django_cfg/apps/payments/admin/payments_admin.py +183 -460
  44. django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
  45. django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
  46. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
  47. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
  48. django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
  49. django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
  50. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
  51. django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
  52. django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
  53. django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
  54. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
  55. django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
  56. django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
  57. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
  58. django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
  59. django_cfg/apps/payments/config/__init__.py +14 -15
  60. django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
  61. django_cfg/apps/payments/config/helpers.py +8 -13
  62. django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
  63. django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
  64. django_cfg/apps/payments/middleware/api_access.py +32 -6
  65. django_cfg/apps/payments/migrations/0001_initial.py +33 -46
  66. django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
  67. django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
  68. django_cfg/apps/payments/models/balance.py +12 -0
  69. django_cfg/apps/payments/models/currencies.py +106 -32
  70. django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
  71. django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
  72. django_cfg/apps/payments/models/payments.py +94 -0
  73. django_cfg/apps/payments/services/core/base.py +4 -4
  74. django_cfg/apps/payments/services/core/currency_service.py +35 -28
  75. django_cfg/apps/payments/services/core/payment_service.py +266 -39
  76. django_cfg/apps/payments/services/providers/__init__.py +3 -0
  77. django_cfg/apps/payments/services/providers/base.py +303 -41
  78. django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
  79. django_cfg/apps/payments/services/providers/models/base.py +145 -0
  80. django_cfg/apps/payments/services/providers/models/providers.py +87 -0
  81. django_cfg/apps/payments/services/providers/models/universal.py +48 -0
  82. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
  83. django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
  84. django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
  85. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
  86. django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
  87. django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
  88. django_cfg/apps/payments/services/providers/registry.py +9 -37
  89. django_cfg/apps/payments/services/providers/sync_service.py +277 -0
  90. django_cfg/apps/payments/services/types/requests.py +19 -7
  91. django_cfg/apps/payments/signals/payment_signals.py +31 -2
  92. django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
  93. django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
  94. django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
  95. django_cfg/apps/payments/tasks/__init__.py +39 -0
  96. django_cfg/apps/payments/tasks/types.py +73 -0
  97. django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
  98. django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
  99. django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
  100. django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
  101. django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
  102. django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
  103. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
  104. django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
  105. django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
  106. django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
  107. django_cfg/apps/payments/urls.py +3 -2
  108. django_cfg/apps/payments/urls_admin.py +1 -1
  109. django_cfg/apps/payments/views/api/currencies.py +8 -5
  110. django_cfg/apps/payments/views/overview/services.py +2 -2
  111. django_cfg/apps/payments/views/serializers/currencies.py +22 -8
  112. django_cfg/apps/support/admin/__init__.py +10 -1
  113. django_cfg/apps/support/admin/support_admin.py +338 -141
  114. django_cfg/apps/tasks/admin/__init__.py +11 -0
  115. django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
  116. django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
  117. django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
  118. django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
  119. django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
  120. django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
  121. django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
  122. django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
  123. django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
  124. django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
  125. django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
  126. django_cfg/apps/tasks/tasks/__init__.py +10 -0
  127. django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
  128. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
  129. django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
  130. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
  131. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
  132. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
  133. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
  134. django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
  135. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
  136. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
  137. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
  138. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
  139. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
  140. django_cfg/apps/tasks/urls.py +2 -2
  141. django_cfg/apps/tasks/urls_admin.py +2 -2
  142. django_cfg/apps/tasks/utils/__init__.py +1 -0
  143. django_cfg/apps/tasks/utils/simulator.py +356 -0
  144. django_cfg/apps/tasks/views/__init__.py +16 -0
  145. django_cfg/apps/tasks/views/api.py +569 -0
  146. django_cfg/apps/tasks/views/dashboard.py +58 -0
  147. django_cfg/config.py +1 -1
  148. django_cfg/core/config.py +10 -5
  149. django_cfg/core/generation.py +1 -1
  150. django_cfg/core/integration/__init__.py +21 -0
  151. django_cfg/management/commands/__init__.py +13 -1
  152. django_cfg/management/commands/migrate_all.py +9 -3
  153. django_cfg/management/commands/migrator.py +11 -6
  154. django_cfg/management/commands/rundramatiq.py +3 -2
  155. django_cfg/management/commands/rundramatiq_simulator.py +430 -0
  156. django_cfg/middleware/__init__.py +0 -2
  157. django_cfg/models/api_keys.py +115 -0
  158. django_cfg/models/constance.py +0 -11
  159. django_cfg/models/payments.py +137 -3
  160. django_cfg/modules/django_admin/__init__.py +64 -0
  161. django_cfg/modules/django_admin/decorators/__init__.py +13 -0
  162. django_cfg/modules/django_admin/decorators/actions.py +106 -0
  163. django_cfg/modules/django_admin/decorators/display.py +106 -0
  164. django_cfg/modules/django_admin/mixins/__init__.py +14 -0
  165. django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
  166. django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
  167. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
  168. django_cfg/modules/django_admin/models/__init__.py +20 -0
  169. django_cfg/modules/django_admin/models/action_models.py +33 -0
  170. django_cfg/modules/django_admin/models/badge_models.py +20 -0
  171. django_cfg/modules/django_admin/models/base.py +26 -0
  172. django_cfg/modules/django_admin/models/display_models.py +31 -0
  173. django_cfg/modules/django_admin/utils/badges.py +159 -0
  174. django_cfg/modules/django_admin/utils/displays.py +247 -0
  175. django_cfg/modules/django_currency/__init__.py +2 -2
  176. django_cfg/modules/django_currency/clients/__init__.py +2 -2
  177. django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
  178. django_cfg/modules/django_currency/core/converter.py +12 -12
  179. django_cfg/modules/django_currency/database/__init__.py +2 -2
  180. django_cfg/modules/django_currency/database/database_loader.py +93 -42
  181. django_cfg/modules/django_llm/llm/client.py +10 -2
  182. django_cfg/modules/django_tasks.py +54 -21
  183. django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
  184. django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
  185. django_cfg/modules/django_unfold/dashboard.py +14 -13
  186. django_cfg/modules/django_unfold/models/config.py +1 -1
  187. django_cfg/registry/core.py +7 -9
  188. django_cfg/registry/third_party.py +2 -2
  189. django_cfg/template_archive/django_sample.zip +0 -0
  190. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
  191. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
  192. django_cfg/apps/accounts/admin/activity.py +0 -96
  193. django_cfg/apps/accounts/admin/group.py +0 -17
  194. django_cfg/apps/accounts/admin/otp.py +0 -59
  195. django_cfg/apps/accounts/admin/registration_source.py +0 -97
  196. django_cfg/apps/accounts/admin/twilio_response.py +0 -227
  197. django_cfg/apps/accounts/admin/user.py +0 -300
  198. django_cfg/apps/agents/core/agent.py +0 -281
  199. django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
  200. django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
  201. django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
  202. django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
  203. django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
  204. django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
  205. django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
  206. django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
  207. django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
  208. django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
  209. django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
  210. django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
  211. django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
  212. django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
  213. django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
  214. django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
  215. django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
  216. django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
  217. django_cfg/apps/payments/config/constance/__init__.py +0 -22
  218. django_cfg/apps/payments/config/constance/config_service.py +0 -123
  219. django_cfg/apps/payments/config/constance/fields.py +0 -69
  220. django_cfg/apps/payments/config/constance/settings.py +0 -160
  221. django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
  222. django_cfg/apps/tasks/admin.py +0 -320
  223. django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
  224. django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
  225. django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
  226. django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
  227. django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
  228. django_cfg/apps/tasks/templates/tasks/base.html +0 -96
  229. django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
  230. django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
  231. django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
  232. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
  233. django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
  234. django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
  235. django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
  236. django_cfg/apps/tasks/views.py +0 -461
  237. django_cfg/management/commands/auto_generate.py +0 -486
  238. django_cfg/middleware/static_nocache.py +0 -55
  239. django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
  240. /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
  241. /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
  242. /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
  243. /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
  244. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
  245. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
  246. {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,247 @@
1
+ """
2
+ Display utilities with humanize integration.
3
+ """
4
+
5
+ import logging
6
+ from typing import Optional, List, Union, Any
7
+ from decimal import Decimal
8
+ from datetime import datetime
9
+
10
+ from django.utils.html import format_html, escape
11
+ from django.utils.safestring import SafeString
12
+ from django.contrib.humanize.templatetags.humanize import naturaltime, intcomma
13
+ from django.utils import timezone
14
+
15
+ from ..models.display_models import UserDisplayConfig, MoneyDisplayConfig, DateTimeDisplayConfig
16
+ from ..icons import Icons
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class UserDisplay:
22
+ """User display utilities."""
23
+
24
+ @classmethod
25
+ def with_avatar(cls, user: Any, config: Optional[UserDisplayConfig] = None) -> List[str]:
26
+ """Display user with avatar for @display(header=True)."""
27
+ config = config or UserDisplayConfig()
28
+
29
+ if not user:
30
+ return ["No user", "", "", {}]
31
+
32
+ name = getattr(user, 'get_full_name', lambda: '')() or getattr(user, 'username', 'Unknown')
33
+ email = getattr(user, 'email', '') if config.show_email else ''
34
+
35
+ # Generate initials
36
+ name_parts = name.split()
37
+ if len(name_parts) >= 2:
38
+ initials = f"{name_parts[0][0]}{name_parts[1][0]}".upper()
39
+ elif name:
40
+ initials = name[0].upper()
41
+ else:
42
+ initials = "U"
43
+
44
+ avatar_data = {"size": config.avatar_size, "initials": initials, "show": config.show_avatar}
45
+
46
+ return [name, email, initials, avatar_data]
47
+
48
+ @classmethod
49
+ def simple(cls, user: Any, config: Optional[UserDisplayConfig] = None) -> SafeString:
50
+ """Simple user display."""
51
+ config = config or UserDisplayConfig()
52
+
53
+ if not user:
54
+ return format_html('<span class="text-font-subtle-light dark:text-font-subtle-dark">No user</span>')
55
+
56
+ name = getattr(user, 'get_full_name', lambda: '')() or getattr(user, 'username', 'Unknown')
57
+ html = format_html('<span class="font-medium">{}</span>', escape(name))
58
+
59
+ if config.show_email:
60
+ email = getattr(user, 'email', '')
61
+ if email:
62
+ html = format_html('{}<br><span class="text-xs text-font-subtle-light dark:text-font-subtle-dark">{}</span>', html, escape(email))
63
+
64
+ return html
65
+
66
+
67
+ class MoneyDisplay:
68
+ """Money display utilities."""
69
+
70
+ @classmethod
71
+ def amount(cls, amount: Union[Decimal, float, int], config: Optional[MoneyDisplayConfig] = None) -> SafeString:
72
+ """Format money amount with smart formatting."""
73
+ config = config or MoneyDisplayConfig()
74
+
75
+ if amount is None:
76
+ return format_html('<span class="text-font-subtle-light dark:text-font-subtle-dark">—</span>')
77
+
78
+ amount = Decimal(str(amount))
79
+
80
+ # Smart decimal places for rates or auto-adjustment
81
+ decimal_places = config.decimal_places
82
+ if config.smart_decimal_places or config.rate_mode:
83
+ if amount >= 1000:
84
+ decimal_places = 0 # 1,234 (whole numbers for large amounts)
85
+ elif amount >= 100:
86
+ decimal_places = 1 # 123.4
87
+ elif amount >= 10:
88
+ decimal_places = 2 # 12.34
89
+ elif amount >= 1:
90
+ decimal_places = 3 # 1.234
91
+ elif amount >= 0.01:
92
+ decimal_places = 4 # 0.1234
93
+ else:
94
+ decimal_places = 8 # 0.00001234 (for very small amounts)
95
+
96
+ # Currency symbols
97
+ symbols = {'USD': '$', 'EUR': '€', 'GBP': '£', 'JPY': '¥', 'BTC': '₿', 'ETH': 'Ξ'}
98
+ symbol = symbols.get(config.currency, config.currency) if config.show_currency_symbol else ""
99
+
100
+ # Format with appropriate decimal places
101
+ if config.thousand_separator:
102
+ if decimal_places == 0:
103
+ formatted_amount = f"{amount:,.0f}"
104
+ else:
105
+ formatted_amount = f"{amount:,.{decimal_places}f}"
106
+ else:
107
+ formatted_amount = f"{amount:.{decimal_places}f}"
108
+
109
+ # Special formatting for rate mode
110
+ if config.rate_mode:
111
+ # For rates, show number + small currency label instead of symbol
112
+ return format_html(
113
+ '<span class="font-mono text-sm">{} <span class="text-font-subtle-light dark:text-font-subtle-dark text-xs">{}</span></span>',
114
+ formatted_amount,
115
+ config.currency
116
+ )
117
+
118
+ # Color coding for regular amounts
119
+ if amount < 0:
120
+ color_class = "text-red-600 dark:text-red-400"
121
+ elif amount == 0:
122
+ color_class = "text-font-default-light dark:text-font-default-dark"
123
+ else:
124
+ color_class = "text-green-600 dark:text-green-400"
125
+
126
+ # Show sign
127
+ sign = "+" if config.show_sign and amount > 0 else ""
128
+
129
+ return format_html('<span class="font-mono {}">{}{}{}</span>', color_class, sign, symbol, formatted_amount)
130
+
131
+ @classmethod
132
+ def with_breakdown(cls, main_amount: Union[Decimal, float, int], breakdown_items: List[dict] = None,
133
+ config: Optional[MoneyDisplayConfig] = None) -> SafeString:
134
+ """Display with breakdown."""
135
+ config = config or MoneyDisplayConfig()
136
+
137
+ html = format_html('<div class="text-right">')
138
+ html += cls.amount(main_amount, config)
139
+
140
+ if breakdown_items:
141
+ for item in breakdown_items:
142
+ label = item.get('label', 'Item')
143
+ amount = item.get('amount', 0)
144
+ color = item.get('color', 'secondary')
145
+
146
+ color_classes = {
147
+ 'success': 'text-green-600 dark:text-green-400',
148
+ 'warning': 'text-yellow-600 dark:text-yellow-400',
149
+ 'danger': 'text-red-600 dark:text-red-400',
150
+ 'secondary': 'text-font-subtle-light dark:text-font-subtle-dark'
151
+ }
152
+
153
+ color_class = color_classes.get(color, 'text-font-subtle-light dark:text-font-subtle-dark')
154
+ html += format_html('<div class="text-xs {}">{}: {}</div>', color_class, escape(label), cls.amount(amount, config))
155
+
156
+ html += format_html('</div>')
157
+ return html
158
+
159
+
160
+ class StatusDisplay:
161
+ """Status display utilities."""
162
+
163
+ @classmethod
164
+ def auto(cls, status: str) -> SafeString:
165
+ """Auto status display with color mapping."""
166
+ if not status:
167
+ return format_html('<span class="text-font-subtle-light dark:text-font-subtle-dark">—</span>')
168
+
169
+ status_lower = status.lower()
170
+
171
+ if any(word in status_lower for word in ['active', 'success', 'completed']):
172
+ variant = 'success'
173
+ icon_name = Icons.CHECK_CIRCLE
174
+ elif any(word in status_lower for word in ['pending', 'processing']):
175
+ variant = 'warning'
176
+ icon_name = Icons.WARNING
177
+ elif any(word in status_lower for word in ['failed', 'error', 'cancelled']):
178
+ variant = 'danger'
179
+ icon_name = Icons.ERROR
180
+ else:
181
+ variant = 'info'
182
+ icon_name = Icons.INFO
183
+
184
+ color_classes = {
185
+ 'success': 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200',
186
+ 'warning': 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200',
187
+ 'danger': 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200',
188
+ 'info': 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200',
189
+ }
190
+
191
+ color_class = color_classes.get(variant, color_classes['info'])
192
+
193
+ # Render icon with Material Icons
194
+ icon_html = format_html('<span class="material-symbols-outlined text-xs mr-1">{}</span>', icon_name)
195
+
196
+ return format_html(
197
+ '<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium {}">'
198
+ '{}{}'
199
+ '</span>',
200
+ color_class, icon_html, escape(status.replace('_', ' ').title())
201
+ )
202
+
203
+
204
+ class DateTimeDisplay:
205
+ """DateTime display utilities."""
206
+
207
+ @classmethod
208
+ def relative(cls, dt: datetime, config: Optional[DateTimeDisplayConfig] = None) -> SafeString:
209
+ """Display with relative time."""
210
+ config = config or DateTimeDisplayConfig()
211
+
212
+ if not dt:
213
+ return format_html('<span class="text-font-subtle-light dark:text-font-subtle-dark">—</span>')
214
+
215
+ absolute_time = dt.strftime(config.datetime_format)
216
+ relative_time = naturaltime(dt)
217
+
218
+ if config.show_relative:
219
+ return format_html(
220
+ '<div class="text-xs"><div class="font-medium">{}</div><div class="text-font-subtle-light dark:text-font-subtle-dark">{}</div></div>',
221
+ escape(absolute_time), escape(relative_time)
222
+ )
223
+ else:
224
+ return format_html('<span class="text-sm">{}</span>', escape(absolute_time))
225
+
226
+ @classmethod
227
+ def compact(cls, dt: datetime, config: Optional[DateTimeDisplayConfig] = None) -> SafeString:
228
+ """Compact datetime display."""
229
+ config = config or DateTimeDisplayConfig()
230
+
231
+ if not dt:
232
+ return format_html('<span class="text-font-subtle-light dark:text-font-subtle-dark">—</span>')
233
+
234
+ now = timezone.now()
235
+ diff = now - dt
236
+
237
+ if diff.days < 1:
238
+ display_text = naturaltime(dt)
239
+ elif diff.days < 7:
240
+ display_text = dt.strftime('%a %H:%M')
241
+ else:
242
+ display_text = dt.strftime('%m/%d/%y')
243
+
244
+ return format_html(
245
+ '<span class="text-xs text-font-default-light dark:text-font-default-dark" title="{}">{}</span>',
246
+ escape(dt.strftime(config.datetime_format)), escape(display_text)
247
+ )
@@ -22,7 +22,7 @@ from .core import (
22
22
  from .utils import CacheManager
23
23
 
24
24
  # Clients
25
- from .clients import YahooFinanceClient, CoinPaprikaClient
25
+ from .clients import HybridCurrencyClient, CoinPaprikaClient
26
26
 
27
27
  # Database tools
28
28
  from .database import (
@@ -95,7 +95,7 @@ __all__ = [
95
95
  "CacheManager",
96
96
 
97
97
  # Clients
98
- "YahooFinanceClient",
98
+ "HybridCurrencyClient",
99
99
  "CoinPaprikaClient",
100
100
 
101
101
  # Database tools
@@ -2,10 +2,10 @@
2
2
  Currency data clients for fetching rates from external APIs.
3
3
  """
4
4
 
5
- from .yahoo_client import YahooFinanceClient
5
+ from .hybrid_client import HybridCurrencyClient
6
6
  from .coinpaprika_client import CoinPaprikaClient
7
7
 
8
8
  __all__ = [
9
- 'YahooFinanceClient',
9
+ 'HybridCurrencyClient',
10
10
  'CoinPaprikaClient'
11
11
  ]