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.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/admin/__init__.py +24 -8
- django_cfg/apps/accounts/admin/activity_admin.py +146 -0
- django_cfg/apps/accounts/admin/filters.py +98 -22
- django_cfg/apps/accounts/admin/group_admin.py +86 -0
- django_cfg/apps/accounts/admin/inlines.py +42 -13
- django_cfg/apps/accounts/admin/otp_admin.py +115 -0
- django_cfg/apps/accounts/admin/registration_admin.py +173 -0
- django_cfg/apps/accounts/admin/resources.py +123 -19
- django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
- django_cfg/apps/accounts/admin/user_admin.py +362 -0
- django_cfg/apps/agents/admin/__init__.py +17 -4
- django_cfg/apps/agents/admin/execution_admin.py +204 -183
- django_cfg/apps/agents/admin/registry_admin.py +230 -255
- django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
- django_cfg/apps/agents/core/__init__.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +221 -0
- django_cfg/apps/agents/core/exceptions.py +14 -0
- django_cfg/apps/agents/core/orchestrator.py +18 -3
- django_cfg/apps/knowbase/admin/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
- django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
- django_cfg/apps/knowbase/admin/document_admin.py +269 -262
- django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
- django_cfg/apps/knowbase/config/settings.py +21 -4
- django_cfg/apps/knowbase/views/chat_views.py +3 -0
- django_cfg/apps/leads/admin/__init__.py +3 -1
- django_cfg/apps/leads/admin/leads_admin.py +235 -35
- django_cfg/apps/maintenance/admin/__init__.py +2 -2
- django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
- django_cfg/apps/maintenance/admin/log_admin.py +143 -61
- django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
- django_cfg/apps/maintenance/admin/site_admin.py +213 -352
- django_cfg/apps/newsletter/admin/__init__.py +29 -2
- django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
- django_cfg/apps/payments/admin/__init__.py +18 -27
- django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
- django_cfg/apps/payments/admin/balance_admin.py +166 -632
- django_cfg/apps/payments/admin/currencies_admin.py +235 -607
- django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
- django_cfg/apps/payments/admin/filters.py +83 -3
- django_cfg/apps/payments/admin/networks_admin.py +269 -0
- django_cfg/apps/payments/admin/payments_admin.py +183 -460
- django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
- django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
- django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
- django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
- django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
- django_cfg/apps/payments/config/__init__.py +14 -15
- django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
- django_cfg/apps/payments/config/helpers.py +8 -13
- django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
- django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
- django_cfg/apps/payments/middleware/api_access.py +32 -6
- django_cfg/apps/payments/migrations/0001_initial.py +33 -46
- django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
- django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
- django_cfg/apps/payments/models/balance.py +12 -0
- django_cfg/apps/payments/models/currencies.py +106 -32
- django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
- django_cfg/apps/payments/models/payments.py +94 -0
- django_cfg/apps/payments/services/core/base.py +4 -4
- django_cfg/apps/payments/services/core/currency_service.py +35 -28
- django_cfg/apps/payments/services/core/payment_service.py +266 -39
- django_cfg/apps/payments/services/providers/__init__.py +3 -0
- django_cfg/apps/payments/services/providers/base.py +303 -41
- django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
- django_cfg/apps/payments/services/providers/models/base.py +145 -0
- django_cfg/apps/payments/services/providers/models/providers.py +87 -0
- django_cfg/apps/payments/services/providers/models/universal.py +48 -0
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
- django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
- django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
- django_cfg/apps/payments/services/providers/registry.py +9 -37
- django_cfg/apps/payments/services/providers/sync_service.py +277 -0
- django_cfg/apps/payments/services/types/requests.py +19 -7
- django_cfg/apps/payments/signals/payment_signals.py +31 -2
- django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
- django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
- django_cfg/apps/payments/tasks/__init__.py +39 -0
- django_cfg/apps/payments/tasks/types.py +73 -0
- django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
- django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
- django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
- django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
- django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
- django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
- django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
- django_cfg/apps/payments/urls.py +3 -2
- django_cfg/apps/payments/urls_admin.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +8 -5
- django_cfg/apps/payments/views/overview/services.py +2 -2
- django_cfg/apps/payments/views/serializers/currencies.py +22 -8
- django_cfg/apps/support/admin/__init__.py +10 -1
- django_cfg/apps/support/admin/support_admin.py +338 -141
- django_cfg/apps/tasks/admin/__init__.py +11 -0
- django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
- django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
- django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
- django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
- django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
- django_cfg/apps/tasks/tasks/__init__.py +10 -0
- django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
- django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
- django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
- django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
- django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
- django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
- django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
- django_cfg/apps/tasks/urls.py +2 -2
- django_cfg/apps/tasks/urls_admin.py +2 -2
- django_cfg/apps/tasks/utils/__init__.py +1 -0
- django_cfg/apps/tasks/utils/simulator.py +356 -0
- django_cfg/apps/tasks/views/__init__.py +16 -0
- django_cfg/apps/tasks/views/api.py +569 -0
- django_cfg/apps/tasks/views/dashboard.py +58 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +10 -5
- django_cfg/core/generation.py +1 -1
- django_cfg/core/integration/__init__.py +21 -0
- django_cfg/management/commands/__init__.py +13 -1
- django_cfg/management/commands/migrate_all.py +9 -3
- django_cfg/management/commands/migrator.py +11 -6
- django_cfg/management/commands/rundramatiq.py +3 -2
- django_cfg/management/commands/rundramatiq_simulator.py +430 -0
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/models/api_keys.py +115 -0
- django_cfg/models/constance.py +0 -11
- django_cfg/models/payments.py +137 -3
- django_cfg/modules/django_admin/__init__.py +64 -0
- django_cfg/modules/django_admin/decorators/__init__.py +13 -0
- django_cfg/modules/django_admin/decorators/actions.py +106 -0
- django_cfg/modules/django_admin/decorators/display.py +106 -0
- django_cfg/modules/django_admin/mixins/__init__.py +14 -0
- django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
- django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
- django_cfg/modules/django_admin/models/__init__.py +20 -0
- django_cfg/modules/django_admin/models/action_models.py +33 -0
- django_cfg/modules/django_admin/models/badge_models.py +20 -0
- django_cfg/modules/django_admin/models/base.py +26 -0
- django_cfg/modules/django_admin/models/display_models.py +31 -0
- django_cfg/modules/django_admin/utils/badges.py +159 -0
- django_cfg/modules/django_admin/utils/displays.py +247 -0
- django_cfg/modules/django_currency/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
- django_cfg/modules/django_currency/core/converter.py +12 -12
- django_cfg/modules/django_currency/database/__init__.py +2 -2
- django_cfg/modules/django_currency/database/database_loader.py +93 -42
- django_cfg/modules/django_llm/llm/client.py +10 -2
- django_cfg/modules/django_tasks.py +54 -21
- django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
- django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
- django_cfg/modules/django_unfold/dashboard.py +14 -13
- django_cfg/modules/django_unfold/models/config.py +1 -1
- django_cfg/registry/core.py +7 -9
- django_cfg/registry/third_party.py +2 -2
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
- django_cfg/apps/accounts/admin/activity.py +0 -96
- django_cfg/apps/accounts/admin/group.py +0 -17
- django_cfg/apps/accounts/admin/otp.py +0 -59
- django_cfg/apps/accounts/admin/registration_source.py +0 -97
- django_cfg/apps/accounts/admin/twilio_response.py +0 -227
- django_cfg/apps/accounts/admin/user.py +0 -300
- django_cfg/apps/agents/core/agent.py +0 -281
- django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
- django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
- django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
- django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
- django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
- django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
- django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
- django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
- django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
- django_cfg/apps/payments/config/constance/__init__.py +0 -22
- django_cfg/apps/payments/config/constance/config_service.py +0 -123
- django_cfg/apps/payments/config/constance/fields.py +0 -69
- django_cfg/apps/payments/config/constance/settings.py +0 -160
- django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
- django_cfg/apps/tasks/admin.py +0 -320
- django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
- django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
- django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
- django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
- django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
- django_cfg/apps/tasks/templates/tasks/base.html +0 -96
- django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
- django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
- django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
- django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
- django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
- django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
- django_cfg/apps/tasks/views.py +0 -461
- django_cfg/management/commands/auto_generate.py +0 -486
- django_cfg/middleware/static_nocache.py +0 -55
- django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
- /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
- {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
|
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
|
-
"
|
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 .
|
5
|
+
from .hybrid_client import HybridCurrencyClient
|
6
6
|
from .coinpaprika_client import CoinPaprikaClient
|
7
7
|
|
8
8
|
__all__ = [
|
9
|
-
'
|
9
|
+
'HybridCurrencyClient',
|
10
10
|
'CoinPaprikaClient'
|
11
11
|
]
|