django-cfg 1.2.31__py3-none-any.whl → 1.3.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 (264) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/api/health/views.py +4 -2
  3. django_cfg/apps/knowbase/config/settings.py +16 -15
  4. django_cfg/apps/payments/README.md +326 -0
  5. django_cfg/apps/payments/admin/__init__.py +20 -10
  6. django_cfg/apps/payments/admin/api_keys_admin.py +521 -237
  7. django_cfg/apps/payments/admin/balance_admin.py +592 -297
  8. django_cfg/apps/payments/admin/currencies_admin.py +526 -222
  9. django_cfg/apps/payments/admin/filters.py +306 -199
  10. django_cfg/apps/payments/admin/payments_admin.py +465 -70
  11. django_cfg/apps/payments/admin/subscriptions_admin.py +578 -128
  12. django_cfg/apps/payments/admin_interface/__init__.py +18 -0
  13. django_cfg/apps/payments/admin_interface/templates/payments/base.html +162 -0
  14. django_cfg/apps/payments/admin_interface/templates/payments/components/dev_tool_card.html +38 -0
  15. django_cfg/apps/payments/admin_interface/templates/payments/components/loading_spinner.html +16 -0
  16. django_cfg/apps/payments/admin_interface/templates/payments/components/notification.html +27 -0
  17. django_cfg/apps/payments/admin_interface/templates/payments/components/provider_card.html +86 -0
  18. django_cfg/apps/payments/admin_interface/templates/payments/components/status_card.html +39 -0
  19. django_cfg/apps/payments/admin_interface/templates/payments/currency_converter.html +382 -0
  20. django_cfg/apps/payments/admin_interface/templates/payments/payment_dashboard.html +300 -0
  21. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +303 -0
  22. django_cfg/apps/payments/admin_interface/templates/payments/payment_list.html +382 -0
  23. django_cfg/apps/payments/admin_interface/templates/payments/payment_status.html +500 -0
  24. django_cfg/apps/payments/admin_interface/templates/payments/webhook_dashboard.html +594 -0
  25. django_cfg/apps/payments/admin_interface/views/__init__.py +23 -0
  26. django_cfg/apps/payments/admin_interface/views/payment_views.py +259 -0
  27. django_cfg/apps/payments/admin_interface/views/webhook_dashboard.py +37 -0
  28. django_cfg/apps/payments/apps.py +34 -9
  29. django_cfg/apps/payments/config/__init__.py +28 -51
  30. django_cfg/apps/payments/config/constance/__init__.py +22 -0
  31. django_cfg/apps/payments/config/constance/config_service.py +123 -0
  32. django_cfg/apps/payments/config/constance/fields.py +69 -0
  33. django_cfg/apps/payments/config/constance/settings.py +160 -0
  34. django_cfg/apps/payments/config/django_cfg_integration.py +202 -0
  35. django_cfg/apps/payments/config/helpers.py +130 -0
  36. django_cfg/apps/payments/management/__init__.py +1 -3
  37. django_cfg/apps/payments/management/commands/__init__.py +1 -3
  38. django_cfg/apps/payments/management/commands/cleanup_expired_data.py +419 -0
  39. django_cfg/apps/payments/management/commands/currency_stats.py +297 -225
  40. django_cfg/apps/payments/management/commands/manage_currencies.py +303 -151
  41. django_cfg/apps/payments/management/commands/manage_providers.py +333 -160
  42. django_cfg/apps/payments/management/commands/process_pending_payments.py +357 -0
  43. django_cfg/apps/payments/management/commands/test_providers.py +434 -0
  44. django_cfg/apps/payments/middleware/__init__.py +3 -1
  45. django_cfg/apps/payments/middleware/api_access.py +329 -222
  46. django_cfg/apps/payments/middleware/rate_limiting.py +342 -152
  47. django_cfg/apps/payments/middleware/usage_tracking.py +249 -240
  48. django_cfg/apps/payments/migrations/0001_initial.py +708 -536
  49. django_cfg/apps/payments/models/__init__.py +13 -18
  50. django_cfg/apps/payments/models/api_keys.py +121 -43
  51. django_cfg/apps/payments/models/balance.py +153 -115
  52. django_cfg/apps/payments/models/base.py +68 -15
  53. django_cfg/apps/payments/models/currencies.py +172 -148
  54. django_cfg/apps/payments/models/managers/__init__.py +44 -0
  55. django_cfg/apps/payments/models/managers/api_key_managers.py +329 -0
  56. django_cfg/apps/payments/models/managers/balance_managers.py +599 -0
  57. django_cfg/apps/payments/models/managers/currency_managers.py +385 -0
  58. django_cfg/apps/payments/models/managers/payment_managers.py +511 -0
  59. django_cfg/apps/payments/models/managers/subscription_managers.py +641 -0
  60. django_cfg/apps/payments/models/payments.py +235 -285
  61. django_cfg/apps/payments/models/subscriptions.py +257 -177
  62. django_cfg/apps/payments/models/tariffs.py +147 -40
  63. django_cfg/apps/payments/services/__init__.py +209 -56
  64. django_cfg/apps/payments/services/cache/__init__.py +6 -6
  65. django_cfg/apps/payments/services/cache_service/__init__.py +143 -0
  66. django_cfg/apps/payments/services/cache_service/api_key_cache.py +37 -0
  67. django_cfg/apps/payments/services/{cache/base.py → cache_service/interfaces.py} +3 -1
  68. django_cfg/apps/payments/services/cache_service/keys.py +49 -0
  69. django_cfg/apps/payments/services/cache_service/rate_limit_cache.py +47 -0
  70. django_cfg/apps/payments/services/cache_service/simple_cache.py +101 -0
  71. django_cfg/apps/payments/services/core/__init__.py +10 -6
  72. django_cfg/apps/payments/services/core/balance_service.py +435 -360
  73. django_cfg/apps/payments/services/core/base.py +166 -0
  74. django_cfg/apps/payments/services/core/currency_service.py +478 -0
  75. django_cfg/apps/payments/services/core/payment_service.py +371 -465
  76. django_cfg/apps/payments/services/core/subscription_service.py +425 -481
  77. django_cfg/apps/payments/services/core/webhook_service.py +410 -0
  78. django_cfg/apps/payments/services/integrations/__init__.py +29 -0
  79. django_cfg/apps/payments/services/integrations/ngrok_service.py +47 -0
  80. django_cfg/apps/payments/services/integrations/providers_config.py +107 -0
  81. django_cfg/apps/payments/services/providers/__init__.py +9 -14
  82. django_cfg/apps/payments/services/providers/base.py +234 -174
  83. django_cfg/apps/payments/services/providers/nowpayments.py +478 -0
  84. django_cfg/apps/payments/services/providers/registry.py +367 -301
  85. django_cfg/apps/payments/services/types/__init__.py +78 -0
  86. django_cfg/apps/payments/services/types/data.py +177 -0
  87. django_cfg/apps/payments/services/types/requests.py +150 -0
  88. django_cfg/apps/payments/services/types/responses.py +156 -0
  89. django_cfg/apps/payments/services/types/webhooks.py +232 -0
  90. django_cfg/apps/payments/signals/__init__.py +33 -8
  91. django_cfg/apps/payments/signals/api_key_signals.py +210 -129
  92. django_cfg/apps/payments/signals/balance_signals.py +174 -0
  93. django_cfg/apps/payments/signals/payment_signals.py +128 -103
  94. django_cfg/apps/payments/signals/subscription_signals.py +194 -142
  95. django_cfg/apps/payments/static/payments/css/components.css +380 -0
  96. django_cfg/apps/payments/static/payments/css/dashboard.css +188 -0
  97. django_cfg/apps/payments/static/payments/js/components.js +545 -0
  98. django_cfg/apps/payments/static/payments/js/utils.js +412 -0
  99. django_cfg/apps/payments/templatetags/__init__.py +1 -1
  100. django_cfg/apps/payments/templatetags/payment_tags.py +466 -0
  101. django_cfg/apps/payments/urls.py +45 -48
  102. django_cfg/apps/payments/urls_admin.py +33 -42
  103. django_cfg/apps/payments/views/api/__init__.py +101 -0
  104. django_cfg/apps/payments/views/api/api_keys.py +387 -0
  105. django_cfg/apps/payments/views/api/balances.py +381 -0
  106. django_cfg/apps/payments/views/api/base.py +298 -0
  107. django_cfg/apps/payments/views/api/currencies.py +402 -0
  108. django_cfg/apps/payments/views/api/payments.py +415 -0
  109. django_cfg/apps/payments/views/api/subscriptions.py +475 -0
  110. django_cfg/apps/payments/views/api/webhooks.py +476 -0
  111. django_cfg/apps/payments/views/serializers/__init__.py +99 -0
  112. django_cfg/apps/payments/views/serializers/api_keys.py +424 -0
  113. django_cfg/apps/payments/views/serializers/balances.py +300 -0
  114. django_cfg/apps/payments/views/serializers/currencies.py +335 -0
  115. django_cfg/apps/payments/views/serializers/payments.py +387 -0
  116. django_cfg/apps/payments/views/serializers/subscriptions.py +429 -0
  117. django_cfg/apps/payments/views/serializers/webhooks.py +137 -0
  118. django_cfg/config.py +1 -1
  119. django_cfg/core/config.py +40 -4
  120. django_cfg/core/generation.py +25 -4
  121. django_cfg/core/integration/README.md +363 -0
  122. django_cfg/core/integration/__init__.py +47 -0
  123. django_cfg/core/integration/commands_collector.py +239 -0
  124. django_cfg/core/integration/display/__init__.py +15 -0
  125. django_cfg/core/integration/display/base.py +157 -0
  126. django_cfg/core/integration/display/ngrok.py +164 -0
  127. django_cfg/core/integration/display/startup.py +815 -0
  128. django_cfg/core/integration/url_integration.py +123 -0
  129. django_cfg/core/integration/version_checker.py +160 -0
  130. django_cfg/management/commands/auto_generate.py +4 -0
  131. django_cfg/management/commands/check_settings.py +6 -0
  132. django_cfg/management/commands/clear_constance.py +5 -2
  133. django_cfg/management/commands/create_token.py +6 -0
  134. django_cfg/management/commands/list_urls.py +6 -0
  135. django_cfg/management/commands/migrate_all.py +6 -0
  136. django_cfg/management/commands/migrator.py +3 -0
  137. django_cfg/management/commands/rundramatiq.py +6 -0
  138. django_cfg/management/commands/runserver_ngrok.py +51 -29
  139. django_cfg/management/commands/script.py +6 -0
  140. django_cfg/management/commands/show_config.py +12 -2
  141. django_cfg/management/commands/show_urls.py +4 -0
  142. django_cfg/management/commands/superuser.py +6 -0
  143. django_cfg/management/commands/task_clear.py +4 -1
  144. django_cfg/management/commands/task_status.py +3 -1
  145. django_cfg/management/commands/test_email.py +3 -0
  146. django_cfg/management/commands/test_telegram.py +6 -0
  147. django_cfg/management/commands/test_twilio.py +6 -0
  148. django_cfg/management/commands/tree.py +6 -0
  149. django_cfg/management/commands/validate_config.py +155 -149
  150. django_cfg/models/constance.py +31 -11
  151. django_cfg/models/payments.py +175 -492
  152. django_cfg/modules/django_logger.py +160 -146
  153. django_cfg/modules/django_unfold/dashboard.py +64 -16
  154. django_cfg/registry/core.py +1 -0
  155. django_cfg/template_archive/django_sample.zip +0 -0
  156. django_cfg/utils/smart_defaults.py +227 -570
  157. django_cfg/utils/toolkit.py +51 -11
  158. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/METADATA +4 -1
  159. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/RECORD +162 -185
  160. django_cfg/apps/payments/__init__.py +0 -8
  161. django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
  162. django_cfg/apps/payments/config/module.py +0 -70
  163. django_cfg/apps/payments/config/providers.py +0 -105
  164. django_cfg/apps/payments/config/settings.py +0 -96
  165. django_cfg/apps/payments/config/utils.py +0 -52
  166. django_cfg/apps/payments/decorators.py +0 -291
  167. django_cfg/apps/payments/management/commands/README.md +0 -146
  168. django_cfg/apps/payments/managers/__init__.py +0 -23
  169. django_cfg/apps/payments/managers/api_key_manager.py +0 -35
  170. django_cfg/apps/payments/managers/balance_manager.py +0 -361
  171. django_cfg/apps/payments/managers/currency_manager.py +0 -306
  172. django_cfg/apps/payments/managers/payment_manager.py +0 -192
  173. django_cfg/apps/payments/managers/subscription_manager.py +0 -37
  174. django_cfg/apps/payments/managers/tariff_manager.py +0 -29
  175. django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +0 -241
  176. django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +0 -30
  177. django_cfg/apps/payments/models/events.py +0 -73
  178. django_cfg/apps/payments/serializers/__init__.py +0 -57
  179. django_cfg/apps/payments/serializers/api_keys.py +0 -51
  180. django_cfg/apps/payments/serializers/balance.py +0 -59
  181. django_cfg/apps/payments/serializers/currencies.py +0 -63
  182. django_cfg/apps/payments/serializers/payments.py +0 -62
  183. django_cfg/apps/payments/serializers/subscriptions.py +0 -71
  184. django_cfg/apps/payments/serializers/tariffs.py +0 -56
  185. django_cfg/apps/payments/services/billing/__init__.py +0 -8
  186. django_cfg/apps/payments/services/cache/simple_cache.py +0 -135
  187. django_cfg/apps/payments/services/core/fallback_service.py +0 -432
  188. django_cfg/apps/payments/services/internal_types.py +0 -461
  189. django_cfg/apps/payments/services/middleware/__init__.py +0 -8
  190. django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
  191. django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -76
  192. django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
  193. django_cfg/apps/payments/services/providers/cryptapi/__init__.py +0 -4
  194. django_cfg/apps/payments/services/providers/cryptapi/config.py +0 -8
  195. django_cfg/apps/payments/services/providers/cryptapi/models.py +0 -192
  196. django_cfg/apps/payments/services/providers/cryptapi/provider.py +0 -439
  197. django_cfg/apps/payments/services/providers/cryptomus/__init__.py +0 -4
  198. django_cfg/apps/payments/services/providers/cryptomus/models.py +0 -176
  199. django_cfg/apps/payments/services/providers/cryptomus/provider.py +0 -429
  200. django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +0 -564
  201. django_cfg/apps/payments/services/providers/models/__init__.py +0 -34
  202. django_cfg/apps/payments/services/providers/models/currencies.py +0 -190
  203. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +0 -4
  204. django_cfg/apps/payments/services/providers/nowpayments/models.py +0 -196
  205. django_cfg/apps/payments/services/providers/nowpayments/provider.py +0 -380
  206. django_cfg/apps/payments/services/providers/stripe/__init__.py +0 -4
  207. django_cfg/apps/payments/services/providers/stripe/models.py +0 -184
  208. django_cfg/apps/payments/services/providers/stripe/provider.py +0 -109
  209. django_cfg/apps/payments/services/security/__init__.py +0 -34
  210. django_cfg/apps/payments/services/security/error_handler.py +0 -635
  211. django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
  212. django_cfg/apps/payments/services/security/webhook_validator.py +0 -474
  213. django_cfg/apps/payments/static/payments/css/payments.css +0 -340
  214. django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
  215. django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
  216. django_cfg/apps/payments/static/payments/js/theme.js +0 -86
  217. django_cfg/apps/payments/tasks/__init__.py +0 -12
  218. django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
  219. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +0 -50
  220. django_cfg/apps/payments/templates/payments/base.html +0 -182
  221. django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
  222. django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
  223. django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -43
  224. django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
  225. django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -34
  226. django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -148
  227. django_cfg/apps/payments/templates/payments/dashboard.html +0 -258
  228. django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +0 -35
  229. django_cfg/apps/payments/templates/payments/payment_create.html +0 -579
  230. django_cfg/apps/payments/templates/payments/payment_detail.html +0 -373
  231. django_cfg/apps/payments/templates/payments/payment_list.html +0 -354
  232. django_cfg/apps/payments/templates/payments/stats.html +0 -261
  233. django_cfg/apps/payments/templates/payments/test.html +0 -213
  234. django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
  235. django_cfg/apps/payments/utils/__init__.py +0 -43
  236. django_cfg/apps/payments/utils/billing_utils.py +0 -342
  237. django_cfg/apps/payments/utils/config_utils.py +0 -239
  238. django_cfg/apps/payments/utils/middleware_utils.py +0 -228
  239. django_cfg/apps/payments/utils/validation_utils.py +0 -94
  240. django_cfg/apps/payments/views/__init__.py +0 -63
  241. django_cfg/apps/payments/views/api_key_views.py +0 -164
  242. django_cfg/apps/payments/views/balance_views.py +0 -75
  243. django_cfg/apps/payments/views/currency_views.py +0 -122
  244. django_cfg/apps/payments/views/payment_views.py +0 -149
  245. django_cfg/apps/payments/views/subscription_views.py +0 -135
  246. django_cfg/apps/payments/views/tariff_views.py +0 -131
  247. django_cfg/apps/payments/views/templates/__init__.py +0 -25
  248. django_cfg/apps/payments/views/templates/ajax.py +0 -451
  249. django_cfg/apps/payments/views/templates/base.py +0 -212
  250. django_cfg/apps/payments/views/templates/dashboard.py +0 -60
  251. django_cfg/apps/payments/views/templates/payment_detail.py +0 -102
  252. django_cfg/apps/payments/views/templates/payment_management.py +0 -158
  253. django_cfg/apps/payments/views/templates/qr_code.py +0 -174
  254. django_cfg/apps/payments/views/templates/stats.py +0 -244
  255. django_cfg/apps/payments/views/templates/utils.py +0 -181
  256. django_cfg/apps/payments/views/webhook_views.py +0 -266
  257. django_cfg/apps/payments/viewsets.py +0 -66
  258. django_cfg/core/integration.py +0 -160
  259. django_cfg/template_archive/.gitignore +0 -1
  260. django_cfg/template_archive/__init__.py +0 -0
  261. django_cfg/urls.py +0 -33
  262. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/WHEEL +0 -0
  263. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/entry_points.txt +0 -0
  264. {django_cfg-1.2.31.dist-info → django_cfg-1.3.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,466 @@
1
+ """
2
+ Universal Payment System v2.0 - Template Tags
3
+
4
+ Custom Django template tags for payment system components.
5
+ """
6
+
7
+ from django import template
8
+ from django.utils.html import format_html
9
+ from django.utils.safestring import mark_safe
10
+ from decimal import Decimal
11
+ import json
12
+
13
+ register = template.Library()
14
+
15
+
16
+ @register.simple_tag
17
+ def material_icon(icon_name, variant='outlined', size='md', css_class=''):
18
+ """
19
+ Render a Material Icon with proper styling.
20
+
21
+ Usage:
22
+ {% material_icon 'payment' %}
23
+ {% material_icon 'check_circle' variant='round' size='lg' css_class='text-green-600' %}
24
+ """
25
+ size_classes = {
26
+ 'xs': 'text-xs',
27
+ 'sm': 'text-sm',
28
+ 'md': 'text-base',
29
+ 'lg': 'text-lg',
30
+ 'xl': 'text-xl',
31
+ '2xl': 'text-2xl'
32
+ }
33
+
34
+ variant_class = f'material-icons-{variant}' if variant != 'filled' else 'material-icons'
35
+ size_class = size_classes.get(size, 'text-base')
36
+
37
+ classes = f'{variant_class} {size_class} {css_class}'.strip()
38
+
39
+ return format_html(
40
+ '<span class="{}">{}</span>',
41
+ classes,
42
+ icon_name
43
+ )
44
+
45
+
46
+ @register.simple_tag
47
+ def status_badge(status, show_icon=True):
48
+ """
49
+ Render a status badge with appropriate styling and icon.
50
+
51
+ Usage:
52
+ {% status_badge payment.status %}
53
+ {% status_badge 'completed' show_icon=False %}
54
+ """
55
+ status_config = {
56
+ 'completed': {
57
+ 'class': 'status-badge success',
58
+ 'icon': 'check_circle',
59
+ 'text': 'Completed'
60
+ },
61
+ 'confirmed': {
62
+ 'class': 'status-badge success',
63
+ 'icon': 'verified',
64
+ 'text': 'Confirmed'
65
+ },
66
+ 'pending': {
67
+ 'class': 'status-badge warning',
68
+ 'icon': 'schedule',
69
+ 'text': 'Pending'
70
+ },
71
+ 'processing': {
72
+ 'class': 'status-badge info',
73
+ 'icon': 'sync',
74
+ 'text': 'Processing'
75
+ },
76
+ 'failed': {
77
+ 'class': 'status-badge error',
78
+ 'icon': 'error',
79
+ 'text': 'Failed'
80
+ },
81
+ 'cancelled': {
82
+ 'class': 'status-badge error',
83
+ 'icon': 'cancel',
84
+ 'text': 'Cancelled'
85
+ },
86
+ 'active': {
87
+ 'class': 'status-badge success',
88
+ 'icon': 'check_circle',
89
+ 'text': 'Active'
90
+ },
91
+ 'inactive': {
92
+ 'class': 'status-badge error',
93
+ 'icon': 'radio_button_unchecked',
94
+ 'text': 'Inactive'
95
+ }
96
+ }
97
+
98
+ config = status_config.get(status.lower(), {
99
+ 'class': 'status-badge info',
100
+ 'icon': 'help',
101
+ 'text': status.title()
102
+ })
103
+
104
+ icon_html = ''
105
+ if show_icon:
106
+ icon_html = format_html(
107
+ '<span class="material-icons-outlined mr-1" style="font-size: 14px;">{}</span>',
108
+ config['icon']
109
+ )
110
+
111
+ return format_html(
112
+ '<span class="{}">{}{}</span>',
113
+ config['class'],
114
+ icon_html,
115
+ config['text']
116
+ )
117
+
118
+
119
+ @register.simple_tag
120
+ def status_indicator(status):
121
+ """
122
+ Render a small status indicator dot.
123
+
124
+ Usage:
125
+ {% status_indicator payment.status %}
126
+ """
127
+ status_classes = {
128
+ 'completed': 'status-active',
129
+ 'confirmed': 'status-active',
130
+ 'active': 'status-active',
131
+ 'pending': 'status-warning',
132
+ 'processing': 'status-warning',
133
+ 'failed': 'status-inactive',
134
+ 'cancelled': 'status-inactive',
135
+ 'inactive': 'status-inactive'
136
+ }
137
+
138
+ css_class = status_classes.get(status.lower(), 'status-warning')
139
+
140
+ return format_html(
141
+ '<span class="status-indicator {}"></span>',
142
+ css_class
143
+ )
144
+
145
+
146
+ @register.simple_tag
147
+ def format_currency(amount, currency='USD', show_symbol=True):
148
+ """
149
+ Format currency amount with proper locale formatting.
150
+
151
+ Usage:
152
+ {% format_currency payment.amount_usd %}
153
+ {% format_currency payment.amount_crypto 'BTC' %}
154
+ """
155
+ try:
156
+ amount = float(amount) if amount else 0
157
+
158
+ if currency == 'USD' and show_symbol:
159
+ return f'${amount:,.2f}'
160
+ elif currency == 'USD':
161
+ return f'{amount:,.2f}'
162
+ else:
163
+ # For crypto currencies, show more decimal places
164
+ if amount >= 1:
165
+ formatted = f'{amount:,.8f}'.rstrip('0').rstrip('.')
166
+ else:
167
+ formatted = f'{amount:.8f}'.rstrip('0').rstrip('.')
168
+
169
+ return f'{formatted} {currency}' if show_symbol else formatted
170
+
171
+ except (ValueError, TypeError):
172
+ return f'0 {currency}' if show_symbol else '0'
173
+
174
+
175
+ @register.simple_tag
176
+ def payment_card(title, icon='payment', content='', css_class=''):
177
+ """
178
+ Render a payment card container.
179
+
180
+ Usage:
181
+ {% payment_card 'Payment Details' 'receipt_long' %}
182
+ """
183
+ return format_html(
184
+ '''
185
+ <div class="payment-card {}">
186
+ <div class="payment-card-header">
187
+ <h2 class="payment-card-title">
188
+ <span class="material-icons-outlined">{}</span>
189
+ {}
190
+ </h2>
191
+ </div>
192
+ <div class="payment-card-content">
193
+ {}
194
+ </div>
195
+ </div>
196
+ ''',
197
+ css_class,
198
+ icon,
199
+ title,
200
+ content
201
+ )
202
+
203
+
204
+ @register.simple_tag
205
+ def copy_button(text, tooltip='Copy to clipboard'):
206
+ """
207
+ Render a copy-to-clipboard button.
208
+
209
+ Usage:
210
+ {% copy_button payment.id %}
211
+ {% copy_button webhook_url 'Copy webhook URL' %}
212
+ """
213
+ return format_html(
214
+ '''
215
+ <button onclick="PaymentSystem.Utils.copyToClipboard('{}')"
216
+ class="btn-icon text-gray-400 hover:text-gray-600 dark:hover:text-gray-200"
217
+ title="{}">
218
+ <span class="material-icons-outlined text-sm">content_copy</span>
219
+ </button>
220
+ ''',
221
+ text,
222
+ tooltip
223
+ )
224
+
225
+
226
+ @register.simple_tag
227
+ def loading_spinner(size='md', text=''):
228
+ """
229
+ Render a loading spinner.
230
+
231
+ Usage:
232
+ {% loading_spinner %}
233
+ {% loading_spinner 'lg' 'Loading...' %}
234
+ """
235
+ spinner_html = format_html(
236
+ '<div class="loading-spinner {}"></div>',
237
+ size
238
+ )
239
+
240
+ if text:
241
+ return format_html(
242
+ '<div class="flex items-center space-x-2">{}<span>{}</span></div>',
243
+ spinner_html,
244
+ text
245
+ )
246
+
247
+ return spinner_html
248
+
249
+
250
+ @register.simple_tag
251
+ def action_button(text, icon, action='', css_class='btn-primary', disabled=False):
252
+ """
253
+ Render an action button with icon.
254
+
255
+ Usage:
256
+ {% action_button 'Create Payment' 'add' 'createPayment()' %}
257
+ {% action_button 'Refresh' 'refresh' css_class='btn-secondary' %}
258
+ """
259
+ disabled_attr = 'disabled' if disabled else ''
260
+ disabled_class = 'opacity-50 cursor-not-allowed' if disabled else ''
261
+
262
+ onclick_attr = f'onclick="{action}"' if action else ''
263
+
264
+ return format_html(
265
+ '''
266
+ <button {} {} class="{} {}">
267
+ <span class="material-icons-outlined">{}</span>
268
+ {}
269
+ </button>
270
+ ''',
271
+ onclick_attr,
272
+ disabled_attr,
273
+ css_class,
274
+ disabled_class,
275
+ icon,
276
+ text
277
+ )
278
+
279
+
280
+ @register.filter
281
+ def json_encode(value):
282
+ """
283
+ JSON encode a value for use in JavaScript.
284
+
285
+ Usage:
286
+ {{ payment_data|json_encode }}
287
+ """
288
+ return mark_safe(json.dumps(value))
289
+
290
+
291
+ @register.filter
292
+ def truncate_id(value, length=8):
293
+ """
294
+ Truncate an ID for display.
295
+
296
+ Usage:
297
+ {{ payment.id|truncate_id }}
298
+ {{ payment.id|truncate_id:12 }}
299
+ """
300
+ if not value:
301
+ return ''
302
+
303
+ str_value = str(value)
304
+ if len(str_value) <= length:
305
+ return str_value
306
+
307
+ return f'{str_value[:length]}...'
308
+
309
+
310
+ @register.filter
311
+ def provider_icon(provider_name):
312
+ """
313
+ Get Material Icon for payment provider.
314
+
315
+ Usage:
316
+ {{ payment.provider|provider_icon }}
317
+ """
318
+ provider_icons = {
319
+ 'nowpayments': 'account_balance',
320
+ 'stripe': 'credit_card',
321
+ 'paypal': 'payment',
322
+ 'cryptapi': 'currency_bitcoin',
323
+ 'cryptomus': 'currency_exchange'
324
+ }
325
+
326
+ return provider_icons.get(provider_name.lower(), 'account_balance')
327
+
328
+
329
+ @register.filter
330
+ def currency_icon(currency_code):
331
+ """
332
+ Get Material Icon for currency.
333
+
334
+ Usage:
335
+ {{ payment.currency.code|currency_icon }}
336
+ """
337
+ currency_icons = {
338
+ 'USD': 'attach_money',
339
+ 'EUR': 'euro',
340
+ 'GBP': 'currency_pound',
341
+ 'BTC': 'currency_bitcoin',
342
+ 'ETH': 'currency_exchange',
343
+ 'LTC': 'currency_exchange',
344
+ 'XRP': 'currency_exchange'
345
+ }
346
+
347
+ return currency_icons.get(currency_code.upper(), 'currency_exchange')
348
+
349
+
350
+ @register.inclusion_tag('payments/components/status_card.html')
351
+ def status_card(title, value, icon='analytics', color_class='text-gray-900 dark:text-white',
352
+ description='', icon_bg_color='blue', status_icon='', action_url='', action_icon='open_in_new'):
353
+ """
354
+ Render a status card component.
355
+
356
+ Usage:
357
+ {% status_card 'Active Payments' payment_count 'payments' 'text-blue-600' 'Currently processing' %}
358
+ """
359
+ return {
360
+ 'title': title,
361
+ 'value': value,
362
+ 'icon': icon,
363
+ 'color_class': color_class,
364
+ 'description': description,
365
+ 'icon_bg_color': icon_bg_color,
366
+ 'status_icon': status_icon,
367
+ 'action_url': action_url,
368
+ 'action_icon': action_icon
369
+ }
370
+
371
+
372
+ @register.inclusion_tag('payments/components/provider_card.html')
373
+ def provider_card(provider):
374
+ """
375
+ Render a provider card component.
376
+
377
+ Usage:
378
+ {% provider_card provider_data %}
379
+ """
380
+ return {'provider': provider}
381
+
382
+
383
+ @register.inclusion_tag('payments/components/loading_spinner.html')
384
+ def loading_component(size='md', text='Loading...'):
385
+ """
386
+ Render a loading spinner component.
387
+
388
+ Usage:
389
+ {% loading_component %}
390
+ {% loading_component 'lg' 'Processing payment...' %}
391
+ """
392
+ return {
393
+ 'size': size,
394
+ 'text': text
395
+ }
396
+
397
+
398
+ @register.simple_tag(takes_context=True)
399
+ def active_nav(context, url_name):
400
+ """
401
+ Check if current URL matches the given URL name.
402
+
403
+ Usage:
404
+ <a href="{% url 'payments:dashboard' %}" class="{% active_nav 'payments:dashboard' %}">
405
+ """
406
+ request = context.get('request')
407
+ if not request:
408
+ return ''
409
+
410
+ try:
411
+ from django.urls import reverse, resolve
412
+ current_url = resolve(request.path_info).url_name
413
+ target_url = url_name.split(':')[-1] # Get the last part after ':'
414
+
415
+ if current_url == target_url:
416
+ return 'text-blue-600 bg-blue-50 dark:bg-blue-900 dark:text-blue-200'
417
+ else:
418
+ return 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white'
419
+ except:
420
+ return 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white'
421
+
422
+
423
+ @register.simple_tag
424
+ def percentage(value, total):
425
+ """
426
+ Calculate percentage.
427
+
428
+ Usage:
429
+ {% percentage successful_payments total_payments %}%
430
+ """
431
+ try:
432
+ if not total or total == 0:
433
+ return 0
434
+ return round((float(value) / float(total)) * 100, 1)
435
+ except (ValueError, TypeError, ZeroDivisionError):
436
+ return 0
437
+
438
+
439
+ @register.filter
440
+ def multiply(value, arg):
441
+ """
442
+ Multiply two values.
443
+
444
+ Usage:
445
+ {{ amount|multiply:exchange_rate }}
446
+ """
447
+ try:
448
+ return float(value) * float(arg)
449
+ except (ValueError, TypeError):
450
+ return 0
451
+
452
+
453
+ @register.filter
454
+ def divide(value, arg):
455
+ """
456
+ Divide two values.
457
+
458
+ Usage:
459
+ {{ total_amount|divide:payment_count }}
460
+ """
461
+ try:
462
+ if float(arg) == 0:
463
+ return 0
464
+ return float(value) / float(arg)
465
+ except (ValueError, TypeError, ZeroDivisionError):
466
+ return 0
@@ -1,80 +1,77 @@
1
1
  """
2
- URL routing for universal payments with nested routers.
2
+ API URL routing for the Universal Payment System v2.0.
3
+
4
+ DRF routing with nested routers and custom endpoints.
3
5
  """
4
6
 
5
7
  from django.urls import path, include
6
8
  from rest_framework.routers import DefaultRouter
7
9
  from rest_framework_nested import routers
8
10
 
9
- from . import views
11
+ from .views.api import (
12
+ PaymentViewSet, UserPaymentViewSet, PaymentCreateView, PaymentStatusView,
13
+ UserBalanceViewSet, TransactionViewSet, UserTransactionViewSet,
14
+ CurrencyViewSet, NetworkViewSet, ProviderCurrencyViewSet, CurrencyConversionView, CurrencyRatesView, SupportedCurrenciesView,
15
+ SubscriptionViewSet, UserSubscriptionViewSet, EndpointGroupViewSet, TariffViewSet,
16
+ APIKeyViewSet, UserAPIKeyViewSet, APIKeyCreateView, APIKeyValidateView,
17
+ UniversalWebhookView, webhook_health_check, webhook_stats, supported_providers,
18
+ )
10
19
 
11
- app_name = 'payments'
20
+ app_name = 'cfg_payments'
12
21
 
13
22
  # Main router for global endpoints
14
23
  router = DefaultRouter()
15
-
16
- # Global ViewSets (without user nesting)
17
- router.register(r'payments', views.UniversalPaymentViewSet, basename='payment')
18
- router.register(r'subscriptions', views.SubscriptionViewSet, basename='subscription')
19
- router.register(r'api-keys', views.APIKeyViewSet, basename='apikey')
20
- router.register(r'balances', views.UserBalanceViewSet, basename='balance')
21
- router.register(r'transactions', views.TransactionViewSet, basename='transaction')
22
- router.register(r'currencies', views.CurrencyViewSet, basename='currency')
23
- router.register(r'networks', views.NetworkViewSet, basename='network')
24
- router.register(r'provider-currencies', views.ProviderCurrencyViewSet, basename='providercurrency')
25
- router.register(r'endpoint-groups', views.EndpointGroupViewSet, basename='endpointgroup')
26
- router.register(r'tariffs', views.TariffViewSet, basename='tariff')
27
- router.register(r'tariff-endpoint-groups', views.TariffEndpointGroupViewSet, basename='tariffendpointgroup')
24
+ router.register(r'payments', PaymentViewSet, basename='payment')
25
+ router.register(r'balances', UserBalanceViewSet, basename='balance')
26
+ router.register(r'transactions', TransactionViewSet, basename='transaction')
27
+ router.register(r'currencies', CurrencyViewSet, basename='currency')
28
+ router.register(r'networks', NetworkViewSet, basename='network')
29
+ router.register(r'provider-currencies', ProviderCurrencyViewSet, basename='provider-currency')
30
+ router.register(r'subscriptions', SubscriptionViewSet, basename='subscription')
31
+ router.register(r'endpoint-groups', EndpointGroupViewSet, basename='endpoint-group')
32
+ router.register(r'tariffs', TariffViewSet, basename='tariff')
33
+ router.register(r'api-keys', APIKeyViewSet, basename='api-key')
28
34
 
29
35
  # Nested routers for user-specific resources
30
- # /users/{user_id}/payments/
31
36
  users_router = routers.SimpleRouter()
32
- users_router.register(r'users', views.UserPaymentViewSet, basename='user')
37
+ users_router.register(r'users', UserPaymentViewSet, basename='user') # Base for nesting
33
38
 
34
39
  payments_router = routers.NestedSimpleRouter(users_router, r'users', lookup='user')
35
- payments_router.register(r'payments', views.UserPaymentViewSet, basename='user-payment')
40
+ payments_router.register(r'payments', UserPaymentViewSet, basename='user-payment')
36
41
 
37
- # /users/{user_id}/subscriptions/
38
42
  subscriptions_router = routers.NestedSimpleRouter(users_router, r'users', lookup='user')
39
- subscriptions_router.register(r'subscriptions', views.UserSubscriptionViewSet, basename='user-subscription')
43
+ subscriptions_router.register(r'subscriptions', UserSubscriptionViewSet, basename='user-subscription')
40
44
 
41
- # /users/{user_id}/api-keys/
42
45
  apikeys_router = routers.NestedSimpleRouter(users_router, r'users', lookup='user')
43
- apikeys_router.register(r'api-keys', views.UserAPIKeyViewSet, basename='user-apikey')
44
-
45
- # Generic API endpoints
46
- generic_patterns = [
47
- # Payment endpoints
48
- path('payment/create/', views.PaymentCreateView.as_view(), name='payment-create'),
49
- path('payment/status/<str:internal_payment_id>/', views.PaymentStatusView.as_view(), name='payment-status'),
50
-
51
- # Subscription endpoints
52
- path('subscription/create/', views.SubscriptionCreateView.as_view(), name='subscription-create'),
53
- path('subscriptions/active/', views.ActiveSubscriptionsView.as_view(), name='subscriptions-active'),
54
-
55
- # API Key endpoints
56
- path('api-key/create/', views.APIKeyCreateView.as_view(), name='apikey-create'),
57
- path('api-key/validate/', views.APIKeyValidateView.as_view(), name='apikey-validate'),
58
-
59
- # Currency endpoints
60
- path('currencies/supported/', views.SupportedCurrenciesView.as_view(), name='currencies-supported'),
61
- path('currencies/rates/', views.CurrencyRatesView.as_view(), name='currency-rates'),
62
-
63
- # Tariff endpoints
64
- path('tariffs/available/', views.AvailableTariffsView.as_view(), name='tariffs-available'),
65
- path('tariffs/comparison/', views.TariffComparisonView.as_view(), name='tariff-comparison'),
66
- ]
46
+ apikeys_router.register(r'api-keys', UserAPIKeyViewSet, basename='user-api-key')
67
47
 
68
48
  urlpatterns = [
69
49
  # Include all router URLs
70
50
  path('', include(router.urls)),
71
51
 
72
52
  # Include nested router URLs
53
+ path('', include(users_router.urls)),
73
54
  path('', include(payments_router.urls)),
74
55
  path('', include(subscriptions_router.urls)),
75
56
  path('', include(apikeys_router.urls)),
76
57
 
77
- # Include generic API endpoints
78
- path('', include(generic_patterns)),
58
+ # Custom API endpoints
59
+ path('payments/create/', PaymentCreateView.as_view(), name='payment-create'),
60
+ path('payments/status/<uuid:pk>/', PaymentStatusView.as_view(), name='payment-status'),
61
+
62
+ path('currencies/convert/', CurrencyConversionView.as_view(), name='currency-convert'),
63
+ path('currencies/rates/', CurrencyRatesView.as_view(), name='currency-rates'),
64
+ path('currencies/supported/', SupportedCurrenciesView.as_view(), name='currencies-supported'),
65
+
66
+ path('api-keys/create/', APIKeyCreateView.as_view(), name='apikey-create'),
67
+ path('api-keys/validate/', APIKeyValidateView.as_view(), name='apikey-validate'),
68
+
69
+ # Webhook endpoints - specific endpoints MUST come before generic <provider> pattern
70
+ path('webhooks/health/', webhook_health_check, name='webhook-health'),
71
+ path('webhooks/stats/', webhook_stats, name='webhook-stats'),
72
+ path('webhooks/providers/', supported_providers, name='webhook-providers'),
73
+ path('webhooks/<str:provider>/', UniversalWebhookView.as_view(), name='webhook-handler'),
79
74
 
75
+ # Health check endpoint
76
+ path('health/', PaymentViewSet.as_view({'get': 'health'}), name='health-check'),
80
77
  ]
@@ -1,58 +1,49 @@
1
1
  """
2
- Template URLs for Payment Dashboard.
2
+ Admin URLs for Universal Payment System v2.0.
3
3
 
4
- All URLs require superuser access as this is an internal admin tool.
4
+ Internal dashboard and management interfaces.
5
+ All URLs require staff/superuser access.
5
6
  """
6
7
 
7
- from django.urls import path
8
- from .views.templates import (
9
- PaymentDashboardView,
10
- PaymentDetailView,
11
- PaymentCreateView,
12
- PaymentStatsView,
8
+ from django.urls import path, include
9
+ from django.contrib.admin.views.decorators import staff_member_required
10
+
11
+ from .admin_interface.views import (
12
+ WebhookDashboardView,
13
+ PaymentFormView,
14
+ PaymentStatusView,
13
15
  PaymentListView,
14
- PaymentQRCodeView,
15
- PaymentTestView,
16
- payment_status_ajax,
17
- payment_events_ajax,
18
- )
19
- from .views.templates.ajax import (
20
- payment_stats_ajax,
21
- payment_search_ajax,
22
- payment_action_ajax,
23
- provider_currencies_ajax,
24
- all_providers_data_ajax,
16
+ PaymentDashboardView,
17
+ CurrencyConverterView,
25
18
  )
26
- from .views.templates.qr_code import qr_code_data_ajax
27
19
 
28
- app_name = 'payments_dashboard'
20
+ app_name = 'cfg_payments_admin'
29
21
 
30
22
  urlpatterns = [
31
23
  # Main dashboard
32
- path('', PaymentDashboardView.as_view(), name='dashboard'),
33
- path('dashboard/', PaymentDashboardView.as_view(), name='dashboard_alt'),
24
+ path('', staff_member_required(PaymentDashboardView.as_view()), name='dashboard'),
25
+ path('dashboard/', staff_member_required(PaymentDashboardView.as_view()), name='dashboard_alt'),
34
26
 
35
27
  # Payment management
36
- path('list/', PaymentListView.as_view(), name='list'),
37
- path('create/', PaymentCreateView.as_view(), name='create'),
38
- path('stats/', PaymentStatsView.as_view(), name='stats'),
39
-
40
- # Payment details
41
- path('payment/<uuid:pk>/', PaymentDetailView.as_view(), name='detail'),
42
- path('payment/<uuid:pk>/qr/', PaymentQRCodeView.as_view(), name='qr_code'),
28
+ path('payments/', include([
29
+ path('', staff_member_required(PaymentListView.as_view()), name='payment-list'),
30
+ path('create/', staff_member_required(PaymentFormView.as_view()), name='payment-create'),
31
+ path('<uuid:pk>/', staff_member_required(PaymentStatusView.as_view()), name='payment-detail'),
32
+ path('status/<uuid:pk>/', staff_member_required(PaymentStatusView.as_view()), name='payment-status'),
33
+ ])),
43
34
 
44
- # AJAX endpoints
45
- path('ajax/payment/<uuid:payment_id>/status/', payment_status_ajax, name='payment_status_ajax'),
46
- path('ajax/payment/<uuid:payment_id>/events/', payment_events_ajax, name='payment_events_ajax'),
47
- path('ajax/payment/<uuid:payment_id>/qr-data/', qr_code_data_ajax, name='qr_data_ajax'),
48
- path('ajax/payment/<uuid:payment_id>/action/', payment_action_ajax, name='payment_action_ajax'),
49
- path('ajax/stats/', payment_stats_ajax, name='payment_stats_ajax'),
50
- path('ajax/search/', payment_search_ajax, name='payment_search_ajax'),
35
+ # Webhook management
36
+ path('webhooks/', include([
37
+ path('', staff_member_required(WebhookDashboardView.as_view()), name='webhook-dashboard'),
38
+ path('dashboard/', staff_member_required(WebhookDashboardView.as_view()), name='webhook-dashboard-alt'),
39
+ ])),
51
40
 
52
- # Provider and Currency AJAX endpoints
53
- path('ajax/provider/currencies/', provider_currencies_ajax, name='provider_currencies_ajax'),
54
- path('ajax/providers/all/', all_providers_data_ajax, name='all_providers_data_ajax'),
41
+ # Tools and utilities
42
+ path('tools/', include([
43
+ path('converter/', staff_member_required(CurrencyConverterView.as_view()), name='currency-converter'),
44
+ ])),
55
45
 
56
- # Development/testing
57
- path('test/', PaymentTestView.as_view(), name='test'),
46
+ # Development/testing tools (only in DEBUG mode)
47
+ # path('test/', PaymentTestView.as_view(), name='test'),
48
+ # path('debug/', PaymentDebugView.as_view(), name='debug'),
58
49
  ]