django-cfg 1.2.29__py3-none-any.whl → 1.3.1__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 (258) 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 -9
  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 +600 -108
  9. django_cfg/apps/payments/admin/filters.py +306 -199
  10. django_cfg/apps/payments/admin/payments_admin.py +470 -64
  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/manage_currencies.py +381 -0
  39. django_cfg/apps/payments/management/commands/manage_providers.py +408 -0
  40. django_cfg/apps/payments/middleware/__init__.py +3 -1
  41. django_cfg/apps/payments/middleware/api_access.py +329 -222
  42. django_cfg/apps/payments/middleware/rate_limiting.py +343 -163
  43. django_cfg/apps/payments/middleware/usage_tracking.py +250 -238
  44. django_cfg/apps/payments/migrations/0001_initial.py +708 -536
  45. django_cfg/apps/payments/models/__init__.py +16 -20
  46. django_cfg/apps/payments/models/api_keys.py +121 -43
  47. django_cfg/apps/payments/models/balance.py +150 -115
  48. django_cfg/apps/payments/models/base.py +68 -15
  49. django_cfg/apps/payments/models/currencies.py +207 -67
  50. django_cfg/apps/payments/models/managers/__init__.py +44 -0
  51. django_cfg/apps/payments/models/managers/api_key_managers.py +329 -0
  52. django_cfg/apps/payments/models/managers/balance_managers.py +599 -0
  53. django_cfg/apps/payments/models/managers/currency_managers.py +385 -0
  54. django_cfg/apps/payments/models/managers/payment_managers.py +511 -0
  55. django_cfg/apps/payments/models/managers/subscription_managers.py +641 -0
  56. django_cfg/apps/payments/models/payments.py +235 -284
  57. django_cfg/apps/payments/models/subscriptions.py +257 -177
  58. django_cfg/apps/payments/models/tariffs.py +147 -40
  59. django_cfg/apps/payments/services/__init__.py +209 -56
  60. django_cfg/apps/payments/services/cache/__init__.py +6 -6
  61. django_cfg/apps/payments/services/cache/{simple_cache.py → cache_service.py} +112 -12
  62. django_cfg/apps/payments/services/core/__init__.py +10 -6
  63. django_cfg/apps/payments/services/core/balance_service.py +435 -360
  64. django_cfg/apps/payments/services/core/base.py +166 -0
  65. django_cfg/apps/payments/services/core/currency_service.py +478 -0
  66. django_cfg/apps/payments/services/core/payment_service.py +344 -468
  67. django_cfg/apps/payments/services/core/subscription_service.py +425 -484
  68. django_cfg/apps/payments/services/core/webhook_service.py +410 -0
  69. django_cfg/apps/payments/services/integrations/__init__.py +29 -0
  70. django_cfg/apps/payments/services/integrations/ngrok_service.py +47 -0
  71. django_cfg/apps/payments/services/integrations/providers_config.py +107 -0
  72. django_cfg/apps/payments/services/providers/__init__.py +9 -14
  73. django_cfg/apps/payments/services/providers/base.py +232 -71
  74. django_cfg/apps/payments/services/providers/nowpayments.py +404 -219
  75. django_cfg/apps/payments/services/providers/registry.py +429 -80
  76. django_cfg/apps/payments/services/types/__init__.py +78 -0
  77. django_cfg/apps/payments/services/types/data.py +177 -0
  78. django_cfg/apps/payments/services/types/requests.py +150 -0
  79. django_cfg/apps/payments/services/types/responses.py +156 -0
  80. django_cfg/apps/payments/services/types/webhooks.py +232 -0
  81. django_cfg/apps/payments/signals/__init__.py +33 -8
  82. django_cfg/apps/payments/signals/api_key_signals.py +211 -130
  83. django_cfg/apps/payments/signals/balance_signals.py +174 -0
  84. django_cfg/apps/payments/signals/payment_signals.py +129 -98
  85. django_cfg/apps/payments/signals/subscription_signals.py +195 -143
  86. django_cfg/apps/payments/static/payments/css/components.css +380 -0
  87. django_cfg/apps/payments/static/payments/css/dashboard.css +188 -0
  88. django_cfg/apps/payments/static/payments/js/components.js +545 -0
  89. django_cfg/apps/payments/static/payments/js/utils.js +412 -0
  90. django_cfg/apps/payments/templatetags/__init__.py +1 -1
  91. django_cfg/apps/payments/templatetags/payment_tags.py +466 -0
  92. django_cfg/apps/payments/urls.py +46 -47
  93. django_cfg/apps/payments/urls_admin.py +49 -0
  94. django_cfg/apps/payments/views/api/__init__.py +101 -0
  95. django_cfg/apps/payments/views/api/api_keys.py +387 -0
  96. django_cfg/apps/payments/views/api/balances.py +381 -0
  97. django_cfg/apps/payments/views/api/base.py +298 -0
  98. django_cfg/apps/payments/views/api/currencies.py +402 -0
  99. django_cfg/apps/payments/views/api/payments.py +415 -0
  100. django_cfg/apps/payments/views/api/subscriptions.py +475 -0
  101. django_cfg/apps/payments/views/api/webhooks.py +476 -0
  102. django_cfg/apps/payments/views/serializers/__init__.py +99 -0
  103. django_cfg/apps/payments/views/serializers/api_keys.py +424 -0
  104. django_cfg/apps/payments/views/serializers/balances.py +300 -0
  105. django_cfg/apps/payments/views/serializers/currencies.py +335 -0
  106. django_cfg/apps/payments/views/serializers/payments.py +387 -0
  107. django_cfg/apps/payments/views/serializers/subscriptions.py +429 -0
  108. django_cfg/apps/payments/views/serializers/webhooks.py +137 -0
  109. django_cfg/apps/tasks/urls.py +0 -2
  110. django_cfg/apps/tasks/urls_admin.py +14 -0
  111. django_cfg/apps/urls.py +4 -4
  112. django_cfg/config.py +1 -1
  113. django_cfg/core/config.py +75 -4
  114. django_cfg/core/generation.py +25 -4
  115. django_cfg/core/integration/README.md +363 -0
  116. django_cfg/core/integration/__init__.py +47 -0
  117. django_cfg/core/integration/commands_collector.py +239 -0
  118. django_cfg/core/integration/display/__init__.py +15 -0
  119. django_cfg/core/integration/display/base.py +157 -0
  120. django_cfg/core/integration/display/ngrok.py +164 -0
  121. django_cfg/core/integration/display/startup.py +815 -0
  122. django_cfg/core/integration/url_integration.py +123 -0
  123. django_cfg/core/integration/version_checker.py +160 -0
  124. django_cfg/management/commands/auto_generate.py +4 -0
  125. django_cfg/management/commands/check_settings.py +6 -0
  126. django_cfg/management/commands/clear_constance.py +5 -2
  127. django_cfg/management/commands/create_token.py +6 -0
  128. django_cfg/management/commands/list_urls.py +6 -0
  129. django_cfg/management/commands/migrate_all.py +6 -0
  130. django_cfg/management/commands/migrator.py +3 -0
  131. django_cfg/management/commands/rundramatiq.py +6 -0
  132. django_cfg/management/commands/runserver_ngrok.py +51 -29
  133. django_cfg/management/commands/script.py +6 -0
  134. django_cfg/management/commands/show_config.py +12 -2
  135. django_cfg/management/commands/show_urls.py +4 -0
  136. django_cfg/management/commands/superuser.py +6 -0
  137. django_cfg/management/commands/task_clear.py +4 -1
  138. django_cfg/management/commands/task_status.py +3 -1
  139. django_cfg/management/commands/test_email.py +3 -0
  140. django_cfg/management/commands/test_telegram.py +6 -0
  141. django_cfg/management/commands/test_twilio.py +6 -0
  142. django_cfg/management/commands/tree.py +6 -0
  143. django_cfg/management/commands/validate_config.py +155 -149
  144. django_cfg/models/constance.py +31 -11
  145. django_cfg/models/payments.py +175 -498
  146. django_cfg/modules/django_currency/__init__.py +16 -11
  147. django_cfg/modules/django_currency/clients/__init__.py +4 -4
  148. django_cfg/modules/django_currency/clients/coinpaprika_client.py +289 -0
  149. django_cfg/modules/django_currency/clients/yahoo_client.py +157 -0
  150. django_cfg/modules/django_currency/core/__init__.py +1 -7
  151. django_cfg/modules/django_currency/core/converter.py +18 -23
  152. django_cfg/modules/django_currency/core/models.py +122 -11
  153. django_cfg/modules/django_currency/database/__init__.py +4 -4
  154. django_cfg/modules/django_currency/database/database_loader.py +190 -309
  155. django_cfg/modules/django_logger.py +160 -146
  156. django_cfg/modules/django_unfold/dashboard.py +65 -12
  157. django_cfg/registry/core.py +1 -0
  158. django_cfg/template_archive/django_sample.zip +0 -0
  159. django_cfg/templates/admin/components/action_grid.html +9 -9
  160. django_cfg/templates/admin/components/metric_card.html +5 -5
  161. django_cfg/templates/admin/components/status_badge.html +2 -2
  162. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +152 -24
  163. django_cfg/templates/admin/snippets/components/quick_actions.html +3 -3
  164. django_cfg/templates/admin/snippets/components/system_health.html +1 -1
  165. django_cfg/templates/admin/snippets/tabs/overview_tab.html +49 -52
  166. django_cfg/utils/smart_defaults.py +222 -571
  167. django_cfg/utils/toolkit.py +51 -11
  168. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/METADATA +5 -4
  169. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/RECORD +172 -182
  170. django_cfg/apps/payments/__init__.py +0 -8
  171. django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
  172. django_cfg/apps/payments/config/module.py +0 -70
  173. django_cfg/apps/payments/config/providers.py +0 -105
  174. django_cfg/apps/payments/config/settings.py +0 -96
  175. django_cfg/apps/payments/config/utils.py +0 -52
  176. django_cfg/apps/payments/decorators.py +0 -291
  177. django_cfg/apps/payments/management/commands/README.md +0 -178
  178. django_cfg/apps/payments/management/commands/currency_stats.py +0 -323
  179. django_cfg/apps/payments/management/commands/populate_currencies.py +0 -246
  180. django_cfg/apps/payments/management/commands/update_currencies.py +0 -336
  181. django_cfg/apps/payments/managers/__init__.py +0 -22
  182. django_cfg/apps/payments/managers/api_key_manager.py +0 -35
  183. django_cfg/apps/payments/managers/balance_manager.py +0 -361
  184. django_cfg/apps/payments/managers/currency_manager.py +0 -83
  185. django_cfg/apps/payments/managers/payment_manager.py +0 -44
  186. django_cfg/apps/payments/managers/subscription_manager.py +0 -37
  187. django_cfg/apps/payments/managers/tariff_manager.py +0 -29
  188. django_cfg/apps/payments/models/events.py +0 -73
  189. django_cfg/apps/payments/serializers/__init__.py +0 -56
  190. django_cfg/apps/payments/serializers/api_keys.py +0 -51
  191. django_cfg/apps/payments/serializers/balance.py +0 -59
  192. django_cfg/apps/payments/serializers/currencies.py +0 -55
  193. django_cfg/apps/payments/serializers/payments.py +0 -62
  194. django_cfg/apps/payments/serializers/subscriptions.py +0 -71
  195. django_cfg/apps/payments/serializers/tariffs.py +0 -56
  196. django_cfg/apps/payments/services/billing/__init__.py +0 -8
  197. django_cfg/apps/payments/services/cache/base.py +0 -30
  198. django_cfg/apps/payments/services/core/fallback_service.py +0 -432
  199. django_cfg/apps/payments/services/internal_types.py +0 -297
  200. django_cfg/apps/payments/services/middleware/__init__.py +0 -8
  201. django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
  202. django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -222
  203. django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
  204. django_cfg/apps/payments/services/providers/cryptapi.py +0 -273
  205. django_cfg/apps/payments/services/providers/cryptomus.py +0 -311
  206. django_cfg/apps/payments/services/security/__init__.py +0 -34
  207. django_cfg/apps/payments/services/security/error_handler.py +0 -637
  208. django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
  209. django_cfg/apps/payments/services/security/webhook_validator.py +0 -475
  210. django_cfg/apps/payments/services/validators/__init__.py +0 -8
  211. django_cfg/apps/payments/static/payments/css/payments.css +0 -340
  212. django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
  213. django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
  214. django_cfg/apps/payments/static/payments/js/theme.js +0 -86
  215. django_cfg/apps/payments/tasks/__init__.py +0 -12
  216. django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
  217. django_cfg/apps/payments/templates/payments/base.html +0 -182
  218. django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
  219. django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
  220. django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -36
  221. django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
  222. django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -27
  223. django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -144
  224. django_cfg/apps/payments/templates/payments/dashboard.html +0 -346
  225. django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
  226. django_cfg/apps/payments/urls_templates.py +0 -52
  227. django_cfg/apps/payments/utils/__init__.py +0 -45
  228. django_cfg/apps/payments/utils/billing_utils.py +0 -342
  229. django_cfg/apps/payments/utils/config_utils.py +0 -245
  230. django_cfg/apps/payments/utils/middleware_utils.py +0 -228
  231. django_cfg/apps/payments/utils/validation_utils.py +0 -94
  232. django_cfg/apps/payments/views/__init__.py +0 -62
  233. django_cfg/apps/payments/views/api_key_views.py +0 -164
  234. django_cfg/apps/payments/views/balance_views.py +0 -75
  235. django_cfg/apps/payments/views/currency_views.py +0 -111
  236. django_cfg/apps/payments/views/payment_views.py +0 -149
  237. django_cfg/apps/payments/views/subscription_views.py +0 -135
  238. django_cfg/apps/payments/views/tariff_views.py +0 -131
  239. django_cfg/apps/payments/views/templates/__init__.py +0 -25
  240. django_cfg/apps/payments/views/templates/ajax.py +0 -312
  241. django_cfg/apps/payments/views/templates/base.py +0 -204
  242. django_cfg/apps/payments/views/templates/dashboard.py +0 -60
  243. django_cfg/apps/payments/views/templates/payment_detail.py +0 -102
  244. django_cfg/apps/payments/views/templates/payment_management.py +0 -164
  245. django_cfg/apps/payments/views/templates/qr_code.py +0 -174
  246. django_cfg/apps/payments/views/templates/stats.py +0 -240
  247. django_cfg/apps/payments/views/templates/utils.py +0 -181
  248. django_cfg/apps/payments/views/webhook_views.py +0 -266
  249. django_cfg/apps/payments/viewsets.py +0 -65
  250. django_cfg/core/integration.py +0 -160
  251. django_cfg/modules/django_currency/clients/coingecko_client.py +0 -257
  252. django_cfg/modules/django_currency/clients/yfinance_client.py +0 -246
  253. django_cfg/template_archive/.gitignore +0 -1
  254. django_cfg/template_archive/__init__.py +0 -0
  255. django_cfg/urls.py +0 -33
  256. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
  257. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
  258. {django_cfg-1.2.29.dist-info → django_cfg-1.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,429 @@
1
+ """
2
+ Subscription serializers for the Universal Payment System v2.0.
3
+
4
+ DRF serializers for subscription operations with service integration.
5
+ """
6
+
7
+ from rest_framework import serializers
8
+ from typing import Dict, Any
9
+ from django.contrib.auth import get_user_model
10
+
11
+ from ...models import Subscription, EndpointGroup, Tariff
12
+ from ...services import get_subscription_service, SubscriptionCreateRequest, SubscriptionUpdateRequest
13
+ from django_cfg.modules.django_logger import get_logger
14
+
15
+ User = get_user_model()
16
+ logger = get_logger("subscription_serializers")
17
+
18
+
19
+ class EndpointGroupSerializer(serializers.ModelSerializer):
20
+ """
21
+ Endpoint group serializer for API access management.
22
+
23
+ Used for subscription endpoint group configuration.
24
+ """
25
+
26
+ class Meta:
27
+ model = EndpointGroup
28
+ fields = [
29
+ 'id',
30
+ 'name',
31
+ 'description',
32
+ 'is_active',
33
+ 'created_at',
34
+ 'updated_at',
35
+ ]
36
+ read_only_fields = fields
37
+
38
+
39
+ class TariffSerializer(serializers.ModelSerializer):
40
+ """
41
+ Tariff serializer for subscription pricing.
42
+
43
+ Used for tariff information and selection.
44
+ """
45
+
46
+ endpoint_groups = EndpointGroupSerializer(many=True, read_only=True)
47
+ endpoint_groups_count = serializers.IntegerField(source='endpoint_groups.count', read_only=True)
48
+
49
+ class Meta:
50
+ model = Tariff
51
+ fields = [
52
+ 'id',
53
+ 'name',
54
+ 'description',
55
+ 'monthly_price',
56
+ 'requests_per_month',
57
+ 'requests_per_minute',
58
+ 'is_active',
59
+ 'endpoint_groups',
60
+ 'endpoint_groups_count',
61
+ 'created_at',
62
+ 'updated_at',
63
+ ]
64
+ read_only_fields = fields
65
+
66
+
67
+ class SubscriptionListSerializer(serializers.ModelSerializer):
68
+ """
69
+ Lightweight subscription serializer for lists.
70
+
71
+ Optimized for subscription lists with minimal data.
72
+ """
73
+
74
+ user = serializers.StringRelatedField(read_only=True)
75
+ tariff_name = serializers.CharField(source='tariff.name', read_only=True)
76
+ status_display = serializers.CharField(source='get_status_display', read_only=True)
77
+ is_active = serializers.BooleanField(source='is_active', read_only=True)
78
+ is_expired = serializers.BooleanField(source='is_expired', read_only=True)
79
+
80
+ class Meta:
81
+ model = Subscription
82
+ fields = [
83
+ 'id',
84
+ 'user',
85
+ 'tariff_name',
86
+ 'status',
87
+ 'status_display',
88
+ 'is_active',
89
+ 'is_expired',
90
+ 'expires_at',
91
+ 'created_at',
92
+ ]
93
+ read_only_fields = fields
94
+
95
+
96
+ class SubscriptionSerializer(serializers.ModelSerializer):
97
+ """
98
+ Complete subscription serializer with full details.
99
+
100
+ Used for subscription detail views and updates.
101
+ """
102
+
103
+ user = serializers.StringRelatedField(read_only=True)
104
+ tariff = TariffSerializer(read_only=True)
105
+ endpoint_group = EndpointGroupSerializer(read_only=True)
106
+ status_display = serializers.CharField(source='get_status_display', read_only=True)
107
+ status_color = serializers.CharField(source='status_color', read_only=True)
108
+
109
+ # Status check methods
110
+ is_active = serializers.BooleanField(source='is_active', read_only=True)
111
+ is_expired = serializers.BooleanField(source='is_expired', read_only=True)
112
+ is_trial = serializers.BooleanField(source='is_trial', read_only=True)
113
+ can_be_renewed = serializers.BooleanField(source='can_be_renewed', read_only=True)
114
+ can_be_cancelled = serializers.BooleanField(source='can_be_cancelled', read_only=True)
115
+
116
+ # Usage statistics
117
+ usage_percentage = serializers.FloatField(source='usage_percentage', read_only=True)
118
+ requests_remaining = serializers.IntegerField(source='requests_remaining', read_only=True)
119
+
120
+ class Meta:
121
+ model = Subscription
122
+ fields = [
123
+ 'id',
124
+ 'user',
125
+ 'tariff',
126
+ 'endpoint_group',
127
+ 'status',
128
+ 'status_display',
129
+ 'status_color',
130
+ 'tier',
131
+ 'total_requests',
132
+ 'requests_used',
133
+ 'requests_remaining',
134
+ 'usage_percentage',
135
+ 'last_request_at',
136
+ 'expires_at',
137
+ 'is_active',
138
+ 'is_expired',
139
+ 'is_trial',
140
+ 'can_be_renewed',
141
+ 'can_be_cancelled',
142
+ 'created_at',
143
+ 'updated_at',
144
+ ]
145
+ read_only_fields = [
146
+ 'id',
147
+ 'user',
148
+ 'total_requests',
149
+ 'requests_used',
150
+ 'requests_remaining',
151
+ 'usage_percentage',
152
+ 'last_request_at',
153
+ 'created_at',
154
+ 'updated_at',
155
+ 'status_display',
156
+ 'status_color',
157
+ 'is_active',
158
+ 'is_expired',
159
+ 'is_trial',
160
+ 'can_be_renewed',
161
+ 'can_be_cancelled',
162
+ ]
163
+
164
+
165
+ class SubscriptionCreateSerializer(serializers.Serializer):
166
+ """
167
+ Subscription creation serializer with service integration.
168
+
169
+ Validates input and delegates to SubscriptionService.
170
+ """
171
+
172
+ tariff_id = serializers.IntegerField(
173
+ min_value=1,
174
+ help_text="Tariff ID for the subscription"
175
+ )
176
+ endpoint_group_id = serializers.IntegerField(
177
+ required=False,
178
+ allow_null=True,
179
+ min_value=1,
180
+ help_text="Endpoint group ID (optional)"
181
+ )
182
+ duration_days = serializers.IntegerField(
183
+ default=30,
184
+ min_value=1,
185
+ max_value=365,
186
+ help_text="Subscription duration in days"
187
+ )
188
+
189
+ def validate_tariff_id(self, value: int) -> int:
190
+ """Validate tariff exists and is active."""
191
+ if not Tariff.objects.filter(id=value, is_active=True).exists():
192
+ raise serializers.ValidationError(f"Tariff {value} not found or inactive")
193
+ return value
194
+
195
+ def validate_endpoint_group_id(self, value: int) -> int:
196
+ """Validate endpoint group exists and is active."""
197
+ if value and not EndpointGroup.objects.filter(id=value, is_active=True).exists():
198
+ raise serializers.ValidationError(f"Endpoint group {value} not found or inactive")
199
+ return value
200
+
201
+ def validate(self, attrs: Dict[str, Any]) -> Dict[str, Any]:
202
+ """Validate subscription creation data."""
203
+ try:
204
+ # Get user from context
205
+ user_id = self.context.get('user_pk') or self.context['request'].user.id
206
+
207
+ # Create Pydantic request for validation
208
+ request = SubscriptionCreateRequest(
209
+ user_id=user_id,
210
+ **attrs
211
+ )
212
+
213
+ # Store validated request for create method
214
+ self._validated_request = request
215
+ return attrs
216
+
217
+ except Exception as e:
218
+ logger.error(f"Subscription validation failed: {e}")
219
+ raise serializers.ValidationError(f"Invalid subscription data: {e}")
220
+
221
+ def create(self, validated_data: Dict[str, Any]) -> Subscription:
222
+ """Create subscription using SubscriptionService."""
223
+ try:
224
+ subscription_service = get_subscription_service()
225
+ result = subscription_service.create_subscription(self._validated_request)
226
+
227
+ if result.success:
228
+ # Get the created subscription from database
229
+ subscription = Subscription.objects.get(id=result.subscription_id)
230
+
231
+ logger.info(f"Subscription created successfully", extra={
232
+ 'subscription_id': result.subscription_id,
233
+ 'user_id': self._validated_request.user_id,
234
+ 'tariff_id': self._validated_request.tariff_id
235
+ })
236
+
237
+ return subscription
238
+ else:
239
+ logger.error(f"Subscription creation failed: {result.message}")
240
+ raise serializers.ValidationError(result.message)
241
+
242
+ except Exception as e:
243
+ logger.error(f"Subscription creation error: {e}")
244
+ raise serializers.ValidationError(f"Subscription creation failed: {e}")
245
+
246
+ def to_representation(self, instance: Subscription) -> Dict[str, Any]:
247
+ """Return full subscription data after creation."""
248
+ return SubscriptionSerializer(instance, context=self.context).data
249
+
250
+
251
+ class SubscriptionUpdateSerializer(serializers.Serializer):
252
+ """
253
+ Subscription update serializer with service integration.
254
+
255
+ Handles subscription modifications through SubscriptionService.
256
+ """
257
+
258
+ action = serializers.ChoiceField(
259
+ choices=[
260
+ ('activate', 'Activate'),
261
+ ('suspend', 'Suspend'),
262
+ ('cancel', 'Cancel'),
263
+ ('renew', 'Renew'),
264
+ ],
265
+ help_text="Action to perform on subscription"
266
+ )
267
+ reason = serializers.CharField(
268
+ required=False,
269
+ allow_blank=True,
270
+ max_length=500,
271
+ help_text="Reason for the action"
272
+ )
273
+ duration_days = serializers.IntegerField(
274
+ required=False,
275
+ min_value=1,
276
+ max_value=365,
277
+ help_text="Duration for renewal (required for renew action)"
278
+ )
279
+
280
+ def validate(self, attrs: Dict[str, Any]) -> Dict[str, Any]:
281
+ """Validate subscription update data."""
282
+ action = attrs.get('action')
283
+ duration_days = attrs.get('duration_days')
284
+
285
+ if action == 'renew' and not duration_days:
286
+ raise serializers.ValidationError("duration_days is required for renew action")
287
+
288
+ return attrs
289
+
290
+ def save(self) -> Dict[str, Any]:
291
+ """Update subscription using SubscriptionService."""
292
+ try:
293
+ subscription_id = self.context.get('subscription_id')
294
+ if not subscription_id:
295
+ raise serializers.ValidationError("Subscription ID is required")
296
+
297
+ subscription_service = get_subscription_service()
298
+ action = self.validated_data['action']
299
+ reason = self.validated_data.get('reason')
300
+ duration_days = self.validated_data.get('duration_days')
301
+
302
+ # Call appropriate service method based on action
303
+ if action == 'activate':
304
+ result = subscription_service.activate_subscription(subscription_id)
305
+ elif action == 'suspend':
306
+ result = subscription_service.suspend_subscription(subscription_id, reason)
307
+ elif action == 'cancel':
308
+ result = subscription_service.cancel_subscription(subscription_id, reason)
309
+ elif action == 'renew':
310
+ result = subscription_service.renew_subscription(subscription_id, duration_days)
311
+ else:
312
+ raise serializers.ValidationError(f"Unknown action: {action}")
313
+
314
+ if result.success:
315
+ # Get updated subscription
316
+ subscription = Subscription.objects.get(id=result.subscription_id)
317
+
318
+ return {
319
+ 'success': True,
320
+ 'message': result.message,
321
+ 'subscription': SubscriptionSerializer(subscription, context=self.context).data
322
+ }
323
+ else:
324
+ return {
325
+ 'success': False,
326
+ 'error': result.message,
327
+ 'error_code': result.error_code
328
+ }
329
+
330
+ except Exception as e:
331
+ logger.error(f"Subscription update error: {e}")
332
+ return {
333
+ 'success': False,
334
+ 'error': f"Subscription update failed: {e}",
335
+ 'error_code': 'subscription_update_error'
336
+ }
337
+
338
+
339
+ class SubscriptionUsageSerializer(serializers.Serializer):
340
+ """
341
+ Subscription usage tracking serializer.
342
+
343
+ Used for incrementing usage counters.
344
+ """
345
+
346
+ endpoint = serializers.CharField(
347
+ required=False,
348
+ allow_blank=True,
349
+ max_length=200,
350
+ help_text="API endpoint used"
351
+ )
352
+
353
+ def save(self) -> Dict[str, Any]:
354
+ """Increment subscription usage using SubscriptionService."""
355
+ try:
356
+ subscription_id = self.context.get('subscription_id')
357
+ if not subscription_id:
358
+ raise serializers.ValidationError("Subscription ID is required")
359
+
360
+ subscription_service = get_subscription_service()
361
+ result = subscription_service.increment_usage(
362
+ subscription_id=subscription_id,
363
+ endpoint=self.validated_data.get('endpoint')
364
+ )
365
+
366
+ if result.success:
367
+ return {
368
+ 'success': True,
369
+ 'message': result.message,
370
+ 'usage': result.data
371
+ }
372
+ else:
373
+ return {
374
+ 'success': False,
375
+ 'error': result.message,
376
+ 'error_code': result.error_code
377
+ }
378
+
379
+ except Exception as e:
380
+ logger.error(f"Usage increment error: {e}")
381
+ return {
382
+ 'success': False,
383
+ 'error': f"Usage increment failed: {e}",
384
+ 'error_code': 'usage_increment_error'
385
+ }
386
+
387
+
388
+ class SubscriptionStatsSerializer(serializers.Serializer):
389
+ """
390
+ Subscription statistics serializer.
391
+
392
+ Used for subscription analytics and reporting.
393
+ """
394
+
395
+ days = serializers.IntegerField(
396
+ default=30,
397
+ min_value=1,
398
+ max_value=365,
399
+ help_text="Number of days to analyze"
400
+ )
401
+
402
+ def save(self) -> Dict[str, Any]:
403
+ """Get subscription statistics using SubscriptionService."""
404
+ try:
405
+ subscription_service = get_subscription_service()
406
+ result = subscription_service.get_subscription_stats(
407
+ days=self.validated_data['days']
408
+ )
409
+
410
+ if result.success:
411
+ return {
412
+ 'success': True,
413
+ 'stats': result.data,
414
+ 'message': result.message
415
+ }
416
+ else:
417
+ return {
418
+ 'success': False,
419
+ 'error': result.message,
420
+ 'error_code': result.error_code
421
+ }
422
+
423
+ except Exception as e:
424
+ logger.error(f"Subscription stats error: {e}")
425
+ return {
426
+ 'success': False,
427
+ 'error': f"Stats generation failed: {e}",
428
+ 'error_code': 'stats_error'
429
+ }
@@ -0,0 +1,137 @@
1
+ """
2
+ Webhook serializers for the Universal Payment System v2.0.
3
+
4
+ DRF serializers for webhook endpoints and data validation.
5
+ """
6
+
7
+ from rest_framework import serializers
8
+ from django_cfg.modules.django_logger import get_logger
9
+
10
+ logger = get_logger(__name__)
11
+
12
+
13
+ class WebhookSerializer(serializers.Serializer):
14
+ """
15
+ Generic webhook serializer.
16
+
17
+ Base serializer for all webhook types.
18
+ """
19
+
20
+ provider = serializers.CharField(max_length=50, help_text="Payment provider name")
21
+ success = serializers.BooleanField(help_text="Processing success status")
22
+ message = serializers.CharField(max_length=500, help_text="Processing message")
23
+
24
+ class Meta:
25
+ fields = ['provider', 'success', 'message']
26
+
27
+
28
+ class WebhookDataSerializer(serializers.Serializer):
29
+ """
30
+ Serializer for incoming webhook data.
31
+
32
+ Generic webhook data structure for all providers.
33
+ """
34
+
35
+ provider = serializers.CharField(max_length=50, help_text="Payment provider name")
36
+ payment_id = serializers.CharField(max_length=256, help_text="Provider payment ID")
37
+ status = serializers.CharField(max_length=50, help_text="Payment status")
38
+ amount = serializers.DecimalField(max_digits=20, decimal_places=8, required=False, help_text="Payment amount")
39
+ currency = serializers.CharField(max_length=10, required=False, help_text="Payment currency")
40
+ transaction_hash = serializers.CharField(max_length=256, required=False, help_text="Blockchain transaction hash")
41
+ confirmations = serializers.IntegerField(required=False, help_text="Number of confirmations")
42
+
43
+ # Raw webhook data
44
+ raw_data = serializers.JSONField(help_text="Raw webhook payload")
45
+
46
+ class Meta:
47
+ fields = [
48
+ 'provider', 'payment_id', 'status', 'amount',
49
+ 'currency', 'transaction_hash', 'confirmations', 'raw_data'
50
+ ]
51
+
52
+
53
+ class WebhookResponseSerializer(serializers.Serializer):
54
+ """
55
+ Serializer for webhook processing response.
56
+
57
+ Standard response format for all webhook endpoints.
58
+ """
59
+
60
+ success = serializers.BooleanField(help_text="Whether webhook was processed successfully")
61
+ message = serializers.CharField(max_length=500, help_text="Processing result message")
62
+ payment_id = serializers.CharField(max_length=256, required=False, help_text="Internal payment ID")
63
+ provider_payment_id = serializers.CharField(max_length=256, required=False, help_text="Provider payment ID")
64
+ processed_at = serializers.DateTimeField(required=False, help_text="Processing timestamp")
65
+
66
+ class Meta:
67
+ fields = ['success', 'message', 'payment_id', 'provider_payment_id', 'processed_at']
68
+
69
+
70
+ class WebhookHealthSerializer(serializers.Serializer):
71
+ """
72
+ Serializer for webhook health check response.
73
+ """
74
+
75
+ status = serializers.CharField(max_length=20, help_text="Health status")
76
+ timestamp = serializers.DateTimeField(help_text="Check timestamp")
77
+ providers = serializers.JSONField(help_text="Provider health status")
78
+
79
+ class Meta:
80
+ fields = ['status', 'timestamp', 'providers']
81
+
82
+
83
+ class WebhookStatsSerializer(serializers.Serializer):
84
+ """
85
+ Serializer for webhook statistics response.
86
+ """
87
+
88
+ total_webhooks = serializers.IntegerField(help_text="Total webhooks processed")
89
+ successful_webhooks = serializers.IntegerField(help_text="Successfully processed webhooks")
90
+ failed_webhooks = serializers.IntegerField(help_text="Failed webhook processing attempts")
91
+ success_rate = serializers.FloatField(help_text="Success rate percentage")
92
+ providers = serializers.JSONField(help_text="Per-provider statistics")
93
+
94
+ class Meta:
95
+ fields = ['total_webhooks', 'successful_webhooks', 'failed_webhooks', 'success_rate', 'providers']
96
+
97
+
98
+ class SupportedProvidersSerializer(serializers.Serializer):
99
+ """
100
+ Serializer for supported providers response.
101
+ """
102
+
103
+ success = serializers.BooleanField(help_text="Request success status")
104
+ providers = serializers.JSONField(help_text="List of supported providers")
105
+ total_count = serializers.IntegerField(help_text="Total number of providers")
106
+ timestamp = serializers.DateTimeField(help_text="Response timestamp")
107
+
108
+ class Meta:
109
+ fields = ['success', 'providers', 'total_count', 'timestamp']
110
+
111
+
112
+ class NowPaymentsWebhookSerializer(serializers.Serializer):
113
+ """
114
+ Serializer for NowPayments webhook data.
115
+
116
+ Specific to NowPayments IPN format.
117
+ """
118
+
119
+ payment_id = serializers.CharField(max_length=256, help_text="NowPayments payment ID")
120
+ payment_status = serializers.CharField(max_length=50, help_text="Payment status")
121
+ pay_address = serializers.CharField(max_length=256, required=False, help_text="Payment address")
122
+ price_amount = serializers.DecimalField(max_digits=20, decimal_places=8, required=False, help_text="Price amount")
123
+ price_currency = serializers.CharField(max_length=10, required=False, help_text="Price currency")
124
+ pay_amount = serializers.DecimalField(max_digits=20, decimal_places=8, required=False, help_text="Pay amount")
125
+ pay_currency = serializers.CharField(max_length=10, required=False, help_text="Pay currency")
126
+ order_id = serializers.CharField(max_length=256, required=False, help_text="Order ID")
127
+ order_description = serializers.CharField(max_length=500, required=False, help_text="Order description")
128
+ purchase_id = serializers.CharField(max_length=256, required=False, help_text="Purchase ID")
129
+ outcome_amount = serializers.DecimalField(max_digits=20, decimal_places=8, required=False, help_text="Outcome amount")
130
+ outcome_currency = serializers.CharField(max_length=10, required=False, help_text="Outcome currency")
131
+
132
+ class Meta:
133
+ fields = [
134
+ 'payment_id', 'payment_status', 'pay_address', 'price_amount', 'price_currency',
135
+ 'pay_amount', 'pay_currency', 'order_id', 'order_description', 'purchase_id',
136
+ 'outcome_amount', 'outcome_currency'
137
+ ]
@@ -18,6 +18,4 @@ urlpatterns = [
18
18
  # RESTful API endpoints using ViewSets
19
19
  path('api/', include(router.urls)),
20
20
 
21
- # Dashboard view
22
- path('dashboard/', views.dashboard_view, name='dashboard'),
23
21
  ]
@@ -0,0 +1,14 @@
1
+ """
2
+ URLs for Django CFG Tasks app.
3
+
4
+ Provides RESTful endpoints for task queue management and monitoring using ViewSets and routers.
5
+ """
6
+
7
+ from django.urls import path
8
+ from . import views
9
+
10
+ urlpatterns = [
11
+
12
+ # Dashboard view
13
+ path('dashboard/', views.dashboard_view, name='dashboard'),
14
+ ]
django_cfg/apps/urls.py CHANGED
@@ -46,14 +46,14 @@ def get_django_cfg_urlpatterns() -> List[URLPattern]:
46
46
 
47
47
  # Tasks app - enabled when knowbase or agents are enabled
48
48
  if base_module.should_enable_tasks():
49
- patterns.append(path('tasks/', include('django_cfg.apps.tasks.urls')))
49
+ patterns.append(path('admin/django_cfg_tasks/admin/', include('django_cfg.apps.tasks.urls_admin')))
50
50
 
51
51
  # Maintenance app - multi-site maintenance mode with Cloudflare
52
- if base_module.is_maintenance_enabled():
53
- patterns.append(path('maintenance/', include('django_cfg.apps.maintenance.urls')))
52
+ # if base_module.is_maintenance_enabled():
53
+ # patterns.append(path('admin/django_cfg_maintenance/', include('django_cfg.apps.maintenance.urls_admin')))
54
54
 
55
55
  if base_module.is_payments_enabled():
56
- patterns.append(path('payments/admin/', include('django_cfg.apps.payments.urls_templates')))
56
+ patterns.append(path('admin/django_cfg_payments/admin/', include('django_cfg.apps.payments.urls_admin')))
57
57
 
58
58
  except Exception:
59
59
  # Fallback: include all URLs if config is not available
django_cfg/config.py CHANGED
@@ -10,7 +10,7 @@ from .modules.django_unfold.models.dropdown import SiteDropdownItem
10
10
 
11
11
 
12
12
  # Library configuration
13
- LIB_NAME = "Django CFG"
13
+ LIB_NAME = "django-cfg"
14
14
  LIB_SITE_URL = "https://djangocfg.com"
15
15
  LIB_DOCS_URL = "https://docs.djangocfg.com"
16
16
  LIB_GITHUB_URL = "https://github.com/django-cfg/django-cfg"