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,419 @@
1
+ """
2
+ Cleanup Expired Data Management Command for Universal Payment System v2.0.
3
+
4
+ Clean up expired payments, sessions, and other temporary data.
5
+ """
6
+
7
+ from datetime import timedelta
8
+ from typing import List, Dict, Any, Optional
9
+
10
+ from django.core.management.base import BaseCommand, CommandError
11
+ from django.utils import timezone
12
+ from django.db import transaction
13
+ from django.db.models import Q, Count
14
+ from django.core.cache import cache
15
+
16
+ from django_cfg.modules.django_logger import get_logger
17
+ from django_cfg.apps.payments.models import UniversalPayment, APIKey, Transaction
18
+ from django_cfg.apps.payments.services.cache.cache_service import get_cache_service
19
+
20
+ logger = get_logger("cleanup_expired_data")
21
+
22
+
23
+ class Command(BaseCommand):
24
+ """
25
+ Clean up expired data from the payment system.
26
+
27
+ Features:
28
+ - Remove expired payments
29
+ - Clean up expired API keys
30
+ - Remove old transaction logs
31
+ - Clear stale cache entries
32
+ - Comprehensive logging and statistics
33
+ """
34
+
35
+ help = 'Clean up expired data from the payment system'
36
+
37
+ def add_arguments(self, parser):
38
+ """Add command line arguments."""
39
+ parser.add_argument(
40
+ '--payments-age-days',
41
+ type=int,
42
+ default=30,
43
+ help='Remove failed/expired payments older than N days (default: 30)'
44
+ )
45
+
46
+ parser.add_argument(
47
+ '--transactions-age-days',
48
+ type=int,
49
+ default=90,
50
+ help='Remove old transaction logs older than N days (default: 90)'
51
+ )
52
+
53
+ parser.add_argument(
54
+ '--api-keys',
55
+ action='store_true',
56
+ help='Clean up expired API keys'
57
+ )
58
+
59
+ parser.add_argument(
60
+ '--cache',
61
+ action='store_true',
62
+ help='Clear stale cache entries'
63
+ )
64
+
65
+ parser.add_argument(
66
+ '--all',
67
+ action='store_true',
68
+ help='Clean up all types of expired data'
69
+ )
70
+
71
+ parser.add_argument(
72
+ '--dry-run',
73
+ action='store_true',
74
+ help='Show what would be cleaned without making changes'
75
+ )
76
+
77
+ parser.add_argument(
78
+ '--batch-size',
79
+ type=int,
80
+ default=1000,
81
+ help='Number of records to process in each batch (default: 1000)'
82
+ )
83
+
84
+ parser.add_argument(
85
+ '--verbose',
86
+ action='store_true',
87
+ help='Show detailed cleanup information'
88
+ )
89
+
90
+ def handle(self, *args, **options):
91
+ """Execute the command."""
92
+ try:
93
+ self.options = options
94
+ self.dry_run = options['dry_run']
95
+ self.verbose = options['verbose']
96
+
97
+ self.show_header()
98
+
99
+ # Initialize statistics
100
+ self.stats = {
101
+ 'payments_removed': 0,
102
+ 'transactions_removed': 0,
103
+ 'api_keys_removed': 0,
104
+ 'cache_entries_cleared': 0,
105
+ 'errors': 0
106
+ }
107
+
108
+ # Determine what to clean
109
+ clean_all = options['all']
110
+
111
+ if clean_all or not any([options['api_keys'], options['cache']]):
112
+ # Default: clean payments and transactions
113
+ self.cleanup_expired_payments()
114
+ self.cleanup_old_transactions()
115
+
116
+ if clean_all or options['api_keys']:
117
+ self.cleanup_expired_api_keys()
118
+
119
+ if clean_all or options['cache']:
120
+ self.cleanup_stale_cache()
121
+
122
+ self.show_summary()
123
+
124
+ except Exception as e:
125
+ logger.error(f"Cleanup expired data command failed: {e}")
126
+ raise CommandError(f"Failed to cleanup expired data: {e}")
127
+
128
+ def show_header(self):
129
+ """Display command header."""
130
+ mode = "DRY RUN" if self.dry_run else "LIVE MODE"
131
+ self.stdout.write(
132
+ self.style.SUCCESS("=" * 60)
133
+ )
134
+ self.stdout.write(
135
+ self.style.SUCCESS(f"🧹 CLEANUP EXPIRED DATA - {mode}")
136
+ )
137
+ self.stdout.write(
138
+ self.style.SUCCESS("=" * 60)
139
+ )
140
+ self.stdout.write(f"Started: {timezone.now().strftime('%Y-%m-%d %H:%M:%S UTC')}")
141
+ self.stdout.write("")
142
+
143
+ def cleanup_expired_payments(self):
144
+ """Clean up expired and failed payments."""
145
+ self.stdout.write(self.style.SUCCESS("🗑️ CLEANING UP EXPIRED PAYMENTS"))
146
+ self.stdout.write("-" * 40)
147
+
148
+ # Calculate cutoff date
149
+ cutoff_date = timezone.now() - timedelta(days=self.options['payments_age_days'])
150
+
151
+ # Find payments to remove
152
+ expired_payments = UniversalPayment.objects.filter(
153
+ Q(status__in=['failed', 'expired', 'cancelled']) &
154
+ Q(created_at__lt=cutoff_date)
155
+ )
156
+
157
+ total_count = expired_payments.count()
158
+ self.stdout.write(f"Found {total_count} expired payments to remove")
159
+
160
+ if total_count == 0:
161
+ self.stdout.write(self.style.WARNING("No expired payments to clean up"))
162
+ return
163
+
164
+ if self.dry_run:
165
+ self.stdout.write(f"[DRY RUN] Would remove {total_count} expired payments")
166
+ self.stats['payments_removed'] = total_count
167
+ return
168
+
169
+ # Remove in batches
170
+ batch_size = self.options['batch_size']
171
+ removed_count = 0
172
+
173
+ try:
174
+ while True:
175
+ # Get batch of payments to delete
176
+ batch_ids = list(
177
+ expired_payments.values_list('id', flat=True)[:batch_size]
178
+ )
179
+
180
+ if not batch_ids:
181
+ break
182
+
183
+ with transaction.atomic():
184
+ # Delete the batch
185
+ deleted_count = UniversalPayment.objects.filter(
186
+ id__in=batch_ids
187
+ ).delete()[0]
188
+
189
+ removed_count += deleted_count
190
+
191
+ if self.verbose:
192
+ self.stdout.write(f" Removed batch: {deleted_count} payments")
193
+
194
+ # Update progress
195
+ progress = (removed_count / total_count) * 100
196
+ self.stdout.write(f"Progress: {removed_count}/{total_count} ({progress:.1f}%)")
197
+
198
+ self.stats['payments_removed'] = removed_count
199
+ logger.info(f"Removed {removed_count} expired payments")
200
+
201
+ except Exception as e:
202
+ logger.error(f"Error cleaning up payments: {e}")
203
+ self.stats['errors'] += 1
204
+ self.stdout.write(self.style.ERROR(f"Error: {e}"))
205
+
206
+ self.stdout.write("")
207
+
208
+ def cleanup_old_transactions(self):
209
+ """Clean up old transaction logs."""
210
+ self.stdout.write(self.style.SUCCESS("📋 CLEANING UP OLD TRANSACTIONS"))
211
+ self.stdout.write("-" * 40)
212
+
213
+ # Calculate cutoff date
214
+ cutoff_date = timezone.now() - timedelta(days=self.options['transactions_age_days'])
215
+
216
+ # Find transactions to remove (keep important ones)
217
+ old_transactions = Transaction.objects.filter(
218
+ created_at__lt=cutoff_date
219
+ ).exclude(
220
+ # Keep transactions for completed payments
221
+ payment__status='completed'
222
+ )
223
+
224
+ total_count = old_transactions.count()
225
+ self.stdout.write(f"Found {total_count} old transactions to remove")
226
+
227
+ if total_count == 0:
228
+ self.stdout.write(self.style.WARNING("No old transactions to clean up"))
229
+ return
230
+
231
+ if self.dry_run:
232
+ self.stdout.write(f"[DRY RUN] Would remove {total_count} old transactions")
233
+ self.stats['transactions_removed'] = total_count
234
+ return
235
+
236
+ # Remove in batches
237
+ batch_size = self.options['batch_size']
238
+ removed_count = 0
239
+
240
+ try:
241
+ while True:
242
+ # Get batch of transactions to delete
243
+ batch_ids = list(
244
+ old_transactions.values_list('id', flat=True)[:batch_size]
245
+ )
246
+
247
+ if not batch_ids:
248
+ break
249
+
250
+ with transaction.atomic():
251
+ # Delete the batch
252
+ deleted_count = Transaction.objects.filter(
253
+ id__in=batch_ids
254
+ ).delete()[0]
255
+
256
+ removed_count += deleted_count
257
+
258
+ if self.verbose:
259
+ self.stdout.write(f" Removed batch: {deleted_count} transactions")
260
+
261
+ # Update progress
262
+ progress = (removed_count / total_count) * 100
263
+ self.stdout.write(f"Progress: {removed_count}/{total_count} ({progress:.1f}%)")
264
+
265
+ self.stats['transactions_removed'] = removed_count
266
+ logger.info(f"Removed {removed_count} old transactions")
267
+
268
+ except Exception as e:
269
+ logger.error(f"Error cleaning up transactions: {e}")
270
+ self.stats['errors'] += 1
271
+ self.stdout.write(self.style.ERROR(f"Error: {e}"))
272
+
273
+ self.stdout.write("")
274
+
275
+ def cleanup_expired_api_keys(self):
276
+ """Clean up expired API keys."""
277
+ self.stdout.write(self.style.SUCCESS("🔑 CLEANING UP EXPIRED API KEYS"))
278
+ self.stdout.write("-" * 40)
279
+
280
+ # Find expired API keys
281
+ now = timezone.now()
282
+ expired_keys = APIKey.objects.filter(
283
+ Q(expires_at__lt=now) | Q(is_active=False)
284
+ ).filter(
285
+ # Only remove keys that haven't been used recently
286
+ last_used_at__lt=now - timedelta(days=7)
287
+ )
288
+
289
+ total_count = expired_keys.count()
290
+ self.stdout.write(f"Found {total_count} expired API keys to remove")
291
+
292
+ if total_count == 0:
293
+ self.stdout.write(self.style.WARNING("No expired API keys to clean up"))
294
+ return
295
+
296
+ if self.dry_run:
297
+ self.stdout.write(f"[DRY RUN] Would remove {total_count} expired API keys")
298
+ self.stats['api_keys_removed'] = total_count
299
+ return
300
+
301
+ try:
302
+ # Remove expired keys
303
+ removed_count = expired_keys.delete()[0]
304
+ self.stats['api_keys_removed'] = removed_count
305
+
306
+ self.stdout.write(f"Removed {removed_count} expired API keys")
307
+ logger.info(f"Removed {removed_count} expired API keys")
308
+
309
+ except Exception as e:
310
+ logger.error(f"Error cleaning up API keys: {e}")
311
+ self.stats['errors'] += 1
312
+ self.stdout.write(self.style.ERROR(f"Error: {e}"))
313
+
314
+ self.stdout.write("")
315
+
316
+ def cleanup_stale_cache(self):
317
+ """Clean up stale cache entries."""
318
+ self.stdout.write(self.style.SUCCESS("💾 CLEANING UP STALE CACHE"))
319
+ self.stdout.write("-" * 40)
320
+
321
+ if self.dry_run:
322
+ self.stdout.write("[DRY RUN] Would clear stale cache entries")
323
+ self.stats['cache_entries_cleared'] = 100 # Estimate
324
+ return
325
+
326
+ try:
327
+ # Get cache service
328
+ cache_service = get_cache_service()
329
+
330
+ # Clear payment-related caches
331
+ cache_patterns = [
332
+ 'payment:*',
333
+ 'balance:*',
334
+ 'api_key:*',
335
+ 'currency:*',
336
+ 'provider:*',
337
+ 'rate_limit:*'
338
+ ]
339
+
340
+ cleared_count = 0
341
+
342
+ for pattern in cache_patterns:
343
+ try:
344
+ # Clear cache entries matching pattern
345
+ if hasattr(cache_service, 'clear_pattern'):
346
+ count = cache_service.clear_pattern(pattern)
347
+ cleared_count += count
348
+ if self.verbose:
349
+ self.stdout.write(f" Cleared {count} entries for pattern: {pattern}")
350
+ except Exception as e:
351
+ logger.warning(f"Failed to clear cache pattern {pattern}: {e}")
352
+
353
+ # Fallback: clear all cache if pattern clearing not available
354
+ if cleared_count == 0:
355
+ cache.clear()
356
+ cleared_count = 1 # At least one operation
357
+ self.stdout.write("Cleared all cache entries")
358
+
359
+ self.stats['cache_entries_cleared'] = cleared_count
360
+ logger.info(f"Cleared {cleared_count} cache entries")
361
+
362
+ except Exception as e:
363
+ logger.error(f"Error cleaning up cache: {e}")
364
+ self.stats['errors'] += 1
365
+ self.stdout.write(self.style.ERROR(f"Error: {e}"))
366
+
367
+ self.stdout.write("")
368
+
369
+ def show_summary(self):
370
+ """Display cleanup summary."""
371
+ self.stdout.write(self.style.SUCCESS("📊 CLEANUP SUMMARY"))
372
+ self.stdout.write("-" * 40)
373
+
374
+ summary_items = [
375
+ ("Payments Removed", self.stats['payments_removed']),
376
+ ("Transactions Removed", self.stats['transactions_removed']),
377
+ ("API Keys Removed", self.stats['api_keys_removed']),
378
+ ("Cache Entries Cleared", self.stats['cache_entries_cleared']),
379
+ ("Errors", self.stats['errors']),
380
+ ]
381
+
382
+ for label, count in summary_items:
383
+ if count > 0:
384
+ style = self.style.SUCCESS if label != "Errors" else self.style.ERROR
385
+ self.stdout.write(f"{label:<22}: {style(count)}")
386
+
387
+ # Calculate total items processed
388
+ total_processed = (
389
+ self.stats['payments_removed'] +
390
+ self.stats['transactions_removed'] +
391
+ self.stats['api_keys_removed']
392
+ )
393
+
394
+ if total_processed > 0:
395
+ self.stdout.write("")
396
+ self.stdout.write(f"Total items processed: {self.style.SUCCESS(total_processed)}")
397
+
398
+ # Show completion time
399
+ self.stdout.write("")
400
+ self.stdout.write(f"Completed: {timezone.now().strftime('%Y-%m-%d %H:%M:%S UTC')}")
401
+
402
+ # Show recommendations
403
+ if self.stats['errors'] > 0:
404
+ self.stdout.write("")
405
+ self.stdout.write(
406
+ self.style.WARNING("⚠️ Some cleanup operations had errors. Check logs for details.")
407
+ )
408
+
409
+ if total_processed == 0 and self.stats['errors'] == 0:
410
+ self.stdout.write("")
411
+ self.stdout.write(
412
+ self.style.SUCCESS("✅ No expired data found. System is clean!")
413
+ )
414
+
415
+ if self.dry_run and total_processed > 0:
416
+ self.stdout.write("")
417
+ self.stdout.write(
418
+ self.style.SUCCESS("✅ Dry run completed. Run without --dry-run to apply changes.")
419
+ )