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
@@ -1,7 +1,8 @@
1
- # Generated by Django 5.2.6 on 2025-09-24 07:15
1
+ # Generated by Django 5.2.6 on 2025-09-26 05:27
2
2
 
3
3
  import django.core.validators
4
4
  import django.db.models.deletion
5
+ import django.utils.timezone
5
6
  import uuid
6
7
  from django.conf import settings
7
8
  from django.db import migrations, models
@@ -16,7 +17,7 @@ class Migration(migrations.Migration):
16
17
 
17
18
  operations = [
18
19
  migrations.CreateModel(
19
- name="Currency",
20
+ name="EndpointGroup",
20
21
  fields=[
21
22
  (
22
23
  "id",
@@ -24,18 +25,94 @@ class Migration(migrations.Migration):
24
25
  auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
25
26
  ),
26
27
  ),
27
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
28
+ (
29
+ "name",
30
+ models.CharField(
31
+ help_text="Endpoint group name (e.g., 'Payment API', 'Balance API')",
32
+ max_length=100,
33
+ unique=True,
34
+ ),
35
+ ),
36
+ (
37
+ "code",
38
+ models.CharField(
39
+ help_text="Endpoint group code (e.g., 'payments', 'balance')",
40
+ max_length=50,
41
+ unique=True,
42
+ ),
43
+ ),
44
+ (
45
+ "description",
46
+ models.TextField(
47
+ blank=True, help_text="Description of what this endpoint group provides"
48
+ ),
49
+ ),
50
+ (
51
+ "is_enabled",
52
+ models.BooleanField(
53
+ default=True, help_text="Whether this endpoint group is available"
54
+ ),
55
+ ),
56
+ (
57
+ "requires_subscription",
58
+ models.BooleanField(
59
+ default=True, help_text="Whether access requires an active subscription"
60
+ ),
61
+ ),
62
+ (
63
+ "default_rate_limit",
64
+ models.PositiveIntegerField(
65
+ default=1000, help_text="Default requests per hour for this endpoint group"
66
+ ),
67
+ ),
68
+ ("created_at", models.DateTimeField(auto_now_add=True)),
28
69
  ("updated_at", models.DateTimeField(auto_now=True)),
70
+ ],
71
+ options={
72
+ "verbose_name": "Endpoint Group",
73
+ "verbose_name_plural": "Endpoint Groups",
74
+ "db_table": "payments_endpoint_groups",
75
+ "ordering": ["name"],
76
+ },
77
+ ),
78
+ migrations.CreateModel(
79
+ name="Currency",
80
+ fields=[
81
+ (
82
+ "id",
83
+ models.BigAutoField(
84
+ auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
85
+ ),
86
+ ),
87
+ (
88
+ "created_at",
89
+ models.DateTimeField(
90
+ auto_now_add=True, db_index=True, help_text="When this record was created"
91
+ ),
92
+ ),
93
+ (
94
+ "updated_at",
95
+ models.DateTimeField(
96
+ auto_now=True, help_text="When this record was last updated"
97
+ ),
98
+ ),
29
99
  (
30
100
  "code",
31
101
  models.CharField(
32
- help_text="Currency code (e.g., USD, BTC, ETH)", max_length=10, unique=True
102
+ help_text="Currency code (e.g., BTC, USD, ETH)",
103
+ max_length=10,
104
+ unique=True,
105
+ validators=[
106
+ django.core.validators.MinLengthValidator(3),
107
+ django.core.validators.MaxLengthValidator(10),
108
+ ],
33
109
  ),
34
110
  ),
35
- ("name", models.CharField(help_text="Full currency name", max_length=100)),
36
111
  (
37
- "symbol",
38
- models.CharField(help_text="Currency symbol (e.g., $, ₿, Ξ)", max_length=10),
112
+ "name",
113
+ models.CharField(
114
+ help_text="Full currency name (e.g., Bitcoin, US Dollar)", max_length=100
115
+ ),
39
116
  ),
40
117
  (
41
118
  "currency_type",
@@ -45,52 +122,48 @@ class Migration(migrations.Migration):
45
122
  max_length=10,
46
123
  ),
47
124
  ),
125
+ (
126
+ "symbol",
127
+ models.CharField(
128
+ blank=True, help_text="Currency symbol (e.g., $, ₿, Ξ)", max_length=10
129
+ ),
130
+ ),
48
131
  (
49
132
  "decimal_places",
50
133
  models.PositiveSmallIntegerField(
51
- default=2, help_text="Number of decimal places for this currency"
134
+ default=8, help_text="Number of decimal places for this currency"
52
135
  ),
53
136
  ),
54
137
  (
55
138
  "is_active",
56
139
  models.BooleanField(
57
- default=True, help_text="Whether this currency is active for payments"
58
- ),
59
- ),
60
- (
61
- "min_payment_amount",
62
- models.FloatField(
63
- default=1.0, help_text="Minimum payment amount for this currency"
64
- ),
65
- ),
66
- (
67
- "usd_rate",
68
- models.FloatField(
69
- default=1.0,
70
- help_text="Exchange rate to USD (1 unit of this currency = X USD)",
140
+ default=True, help_text="Whether this currency is available for payments"
71
141
  ),
72
142
  ),
73
143
  (
74
- "rate_updated_at",
75
- models.DateTimeField(
76
- blank=True, help_text="When the exchange rate was last updated", null=True
144
+ "exchange_rate_source",
145
+ models.CharField(
146
+ blank=True,
147
+ help_text="Source for exchange rates (auto-detected by django_currency)",
148
+ max_length=50,
77
149
  ),
78
150
  ),
79
151
  ],
80
152
  options={
81
153
  "verbose_name": "Currency",
82
154
  "verbose_name_plural": "Currencies",
83
- "db_table": "payment_currencies",
84
- "ordering": ["code"],
155
+ "db_table": "payments_currencies",
156
+ "ordering": ["currency_type", "code"],
85
157
  "indexes": [
86
- models.Index(fields=["code"], name="payment_cur_code_e2a506_idx"),
87
- models.Index(fields=["currency_type"], name="payment_cur_currenc_6057a9_idx"),
88
- models.Index(fields=["is_active"], name="payment_cur_is_acti_8d558f_idx"),
158
+ models.Index(
159
+ fields=["currency_type", "is_active"], name="payments_cu_currenc_c67daf_idx"
160
+ ),
161
+ models.Index(fields=["code"], name="payments_cu_code_2e1e62_idx"),
89
162
  ],
90
163
  },
91
164
  ),
92
165
  migrations.CreateModel(
93
- name="EndpointGroup",
166
+ name="Network",
94
167
  fields=[
95
168
  (
96
169
  "id",
@@ -98,158 +171,176 @@ class Migration(migrations.Migration):
98
171
  auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
99
172
  ),
100
173
  ),
101
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
102
- ("updated_at", models.DateTimeField(auto_now=True)),
103
174
  (
104
- "name",
105
- models.CharField(help_text="Endpoint group name", max_length=100, unique=True),
175
+ "created_at",
176
+ models.DateTimeField(
177
+ auto_now_add=True, db_index=True, help_text="When this record was created"
178
+ ),
106
179
  ),
107
- ("display_name", models.CharField(help_text="Human-readable name", max_length=200)),
108
- ("description", models.TextField(blank=True, help_text="Group description")),
109
180
  (
110
- "basic_price",
111
- models.FloatField(
112
- default=0.0,
113
- help_text="Basic tier monthly price",
114
- validators=[django.core.validators.MinValueValidator(0.0)],
181
+ "updated_at",
182
+ models.DateTimeField(
183
+ auto_now=True, help_text="When this record was last updated"
115
184
  ),
116
185
  ),
117
186
  (
118
- "premium_price",
119
- models.FloatField(
120
- default=0.0,
121
- help_text="Premium tier monthly price",
122
- validators=[django.core.validators.MinValueValidator(0.0)],
187
+ "name",
188
+ models.CharField(
189
+ help_text="Network name (e.g., Ethereum, Bitcoin, Polygon)",
190
+ max_length=50,
191
+ unique=True,
123
192
  ),
124
193
  ),
125
194
  (
126
- "enterprise_price",
127
- models.FloatField(
128
- default=0.0,
129
- help_text="Enterprise tier monthly price",
130
- validators=[django.core.validators.MinValueValidator(0.0)],
195
+ "code",
196
+ models.CharField(
197
+ help_text="Network code (e.g., ETH, BTC, MATIC)", max_length=20, unique=True
131
198
  ),
132
199
  ),
133
200
  (
134
- "basic_limit",
135
- models.PositiveIntegerField(
136
- default=1000, help_text="Basic tier monthly usage limit"
201
+ "block_explorer_url",
202
+ models.URLField(
203
+ blank=True,
204
+ help_text="Block explorer URL template (use {tx} for transaction hash)",
137
205
  ),
138
206
  ),
139
207
  (
140
- "premium_limit",
141
- models.PositiveIntegerField(
142
- default=10000, help_text="Premium tier monthly usage limit"
208
+ "is_active",
209
+ models.BooleanField(
210
+ default=True, help_text="Whether this network is available for payments"
143
211
  ),
144
212
  ),
145
213
  (
146
- "enterprise_limit",
214
+ "confirmation_blocks",
147
215
  models.PositiveIntegerField(
148
- default=0, help_text="Enterprise tier monthly usage limit (0 = unlimited)"
216
+ default=1, help_text="Number of confirmations required for this network"
149
217
  ),
150
218
  ),
151
219
  (
152
- "is_active",
153
- models.BooleanField(default=True, help_text="Is this endpoint group active"),
220
+ "average_block_time",
221
+ models.PositiveIntegerField(
222
+ default=600, help_text="Average block time in seconds"
223
+ ),
154
224
  ),
155
225
  (
156
- "require_api_key",
157
- models.BooleanField(default=True, help_text="Require API key for access"),
226
+ "native_currency",
227
+ models.ForeignKey(
228
+ help_text="Native currency of this network",
229
+ on_delete=django.db.models.deletion.PROTECT,
230
+ related_name="native_networks",
231
+ to="payments.currency",
232
+ ),
158
233
  ),
159
234
  ],
160
235
  options={
161
- "verbose_name": "Endpoint Group",
162
- "verbose_name_plural": "Endpoint Groups",
163
- "db_table": "endpoint_groups",
236
+ "verbose_name": "Network",
237
+ "verbose_name_plural": "Networks",
238
+ "db_table": "payments_networks",
164
239
  "ordering": ["name"],
165
- "indexes": [
166
- models.Index(fields=["name"], name="endpoint_gr_name_970d2f_idx"),
167
- models.Index(fields=["is_active"], name="endpoint_gr_is_acti_a9b5f6_idx"),
168
- ],
169
240
  },
170
241
  ),
171
242
  migrations.CreateModel(
172
- name="PaymentEvent",
243
+ name="ProviderCurrency",
173
244
  fields=[
174
245
  (
175
246
  "id",
176
- models.UUIDField(
177
- default=uuid.uuid4,
178
- editable=False,
179
- help_text="Unique identifier",
180
- primary_key=True,
181
- serialize=False,
247
+ models.BigAutoField(
248
+ auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
182
249
  ),
183
250
  ),
184
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
185
- ("updated_at", models.DateTimeField(auto_now=True)),
186
251
  (
187
- "payment_id",
188
- models.CharField(db_index=True, help_text="Payment identifier", max_length=255),
252
+ "created_at",
253
+ models.DateTimeField(
254
+ auto_now_add=True, db_index=True, help_text="When this record was created"
255
+ ),
189
256
  ),
190
257
  (
191
- "event_type",
192
- models.CharField(
193
- choices=[
194
- ("payment_created", "Payment Created"),
195
- ("webhook_received", "Webhook Received"),
196
- ("webhook_processed", "Webhook Processed"),
197
- ("balance_updated", "Balance Updated"),
198
- ("refund_processed", "Refund Processed"),
199
- ("status_changed", "Status Changed"),
200
- ("error_occurred", "Error Occurred"),
201
- ],
202
- db_index=True,
203
- help_text="Type of event",
204
- max_length=50,
258
+ "updated_at",
259
+ models.DateTimeField(
260
+ auto_now=True, help_text="When this record was last updated"
205
261
  ),
206
262
  ),
207
263
  (
208
- "sequence_number",
209
- models.PositiveBigIntegerField(help_text="Sequential number per payment"),
264
+ "provider",
265
+ models.CharField(
266
+ help_text="Payment provider name (e.g., nowpayments)", max_length=50
267
+ ),
210
268
  ),
211
- ("event_data", models.JSONField(help_text="Event data payload")),
212
269
  (
213
- "processed_by",
270
+ "provider_currency_code",
214
271
  models.CharField(
215
- help_text="Worker/server that processed this event", max_length=100
272
+ help_text="Currency code as used by the provider", max_length=20
216
273
  ),
217
274
  ),
218
275
  (
219
- "correlation_id",
220
- models.CharField(
276
+ "min_amount",
277
+ models.DecimalField(
221
278
  blank=True,
222
- help_text="Correlation ID for tracing",
223
- max_length=255,
279
+ decimal_places=8,
280
+ help_text="Minimum payment amount for this currency",
281
+ max_digits=20,
224
282
  null=True,
225
283
  ),
226
284
  ),
227
285
  (
228
- "idempotency_key",
229
- models.CharField(
230
- help_text="Idempotency key to prevent duplicates",
231
- max_length=255,
232
- unique=True,
286
+ "max_amount",
287
+ models.DecimalField(
288
+ blank=True,
289
+ decimal_places=8,
290
+ help_text="Maximum payment amount for this currency",
291
+ max_digits=20,
292
+ null=True,
233
293
  ),
234
294
  ),
235
- ],
236
- options={
237
- "verbose_name": "Payment Event",
238
- "verbose_name_plural": "Payment Events",
239
- "db_table": "payment_events",
240
- "ordering": ["sequence_number"],
241
- "indexes": [
242
- models.Index(
243
- fields=["payment_id", "sequence_number"],
244
- name="payment_eve_payment_aaf2d1_idx",
295
+ (
296
+ "is_enabled",
297
+ models.BooleanField(
298
+ default=True, help_text="Whether this currency is enabled for this provider"
245
299
  ),
246
- models.Index(
247
- fields=["event_type", "created_at"], name="payment_eve_event_t_e821f3_idx"
300
+ ),
301
+ (
302
+ "fee_percentage",
303
+ models.DecimalField(
304
+ decimal_places=4,
305
+ default=0,
306
+ help_text="Fee percentage (0.0250 = 2.5%)",
307
+ max_digits=5,
248
308
  ),
249
- models.Index(fields=["idempotency_key"], name="payment_eve_idempot_c47628_idx"),
250
- models.Index(fields=["correlation_id"], name="payment_eve_correla_fa1dc3_idx"),
251
- models.Index(fields=["created_at"], name="payment_eve_created_0c1f4a_idx"),
252
- ],
309
+ ),
310
+ (
311
+ "fixed_fee",
312
+ models.DecimalField(
313
+ decimal_places=8,
314
+ default=0,
315
+ help_text="Fixed fee amount in this currency",
316
+ max_digits=20,
317
+ ),
318
+ ),
319
+ (
320
+ "currency",
321
+ models.ForeignKey(
322
+ on_delete=django.db.models.deletion.CASCADE,
323
+ related_name="provider_configs",
324
+ to="payments.currency",
325
+ ),
326
+ ),
327
+ (
328
+ "network",
329
+ models.ForeignKey(
330
+ blank=True,
331
+ help_text="Network for crypto currencies (null for fiat)",
332
+ null=True,
333
+ on_delete=django.db.models.deletion.CASCADE,
334
+ related_name="provider_configs",
335
+ to="payments.network",
336
+ ),
337
+ ),
338
+ ],
339
+ options={
340
+ "verbose_name": "Provider Currency",
341
+ "verbose_name_plural": "Provider Currencies",
342
+ "db_table": "payments_provider_currencies",
343
+ "ordering": ["provider", "currency__code"],
253
344
  },
254
345
  ),
255
346
  migrations.CreateModel(
@@ -260,22 +351,33 @@ class Migration(migrations.Migration):
260
351
  models.UUIDField(
261
352
  default=uuid.uuid4,
262
353
  editable=False,
263
- help_text="Unique identifier",
354
+ help_text="Unique identifier for this record",
264
355
  primary_key=True,
265
356
  serialize=False,
266
357
  ),
267
358
  ),
268
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
269
- ("updated_at", models.DateTimeField(auto_now=True)),
359
+ (
360
+ "created_at",
361
+ models.DateTimeField(
362
+ auto_now_add=True, db_index=True, help_text="When this record was created"
363
+ ),
364
+ ),
365
+ (
366
+ "updated_at",
367
+ models.DateTimeField(
368
+ auto_now=True, help_text="When this record was last updated"
369
+ ),
370
+ ),
270
371
  (
271
372
  "tier",
272
373
  models.CharField(
273
374
  choices=[
274
- ("basic", "Basic"),
275
- ("premium", "Premium"),
276
- ("enterprise", "Enterprise"),
375
+ ("free", "Free Tier"),
376
+ ("basic", "Basic Tier"),
377
+ ("pro", "Pro Tier"),
378
+ ("enterprise", "Enterprise Tier"),
277
379
  ],
278
- default="basic",
380
+ default="free",
279
381
  help_text="Subscription tier",
280
382
  max_length=20,
281
383
  ),
@@ -286,9 +388,9 @@ class Migration(migrations.Migration):
286
388
  choices=[
287
389
  ("active", "Active"),
288
390
  ("inactive", "Inactive"),
289
- ("expired", "Expired"),
290
- ("cancelled", "Cancelled"),
291
391
  ("suspended", "Suspended"),
392
+ ("cancelled", "Cancelled"),
393
+ ("expired", "Expired"),
292
394
  ],
293
395
  default="active",
294
396
  help_text="Subscription status",
@@ -296,59 +398,75 @@ class Migration(migrations.Migration):
296
398
  ),
297
399
  ),
298
400
  (
299
- "monthly_price",
300
- models.FloatField(
301
- help_text="Monthly subscription price",
302
- validators=[django.core.validators.MinValueValidator(0.0)],
401
+ "requests_per_hour",
402
+ models.PositiveIntegerField(
403
+ default=100,
404
+ help_text="API requests allowed per hour",
405
+ validators=[
406
+ django.core.validators.MinValueValidator(1),
407
+ django.core.validators.MaxValueValidator(100000),
408
+ ],
303
409
  ),
304
410
  ),
305
411
  (
306
- "usage_limit",
412
+ "requests_per_day",
307
413
  models.PositiveIntegerField(
308
- default=1000, help_text="Monthly usage limit (0 = unlimited)"
414
+ default=1000,
415
+ help_text="API requests allowed per day",
416
+ validators=[
417
+ django.core.validators.MinValueValidator(1),
418
+ django.core.validators.MaxValueValidator(1000000),
419
+ ],
309
420
  ),
310
421
  ),
311
422
  (
312
- "usage_current",
313
- models.PositiveIntegerField(default=0, help_text="Current month usage"),
423
+ "starts_at",
424
+ models.DateTimeField(
425
+ default=django.utils.timezone.now, help_text="When this subscription starts"
426
+ ),
314
427
  ),
428
+ ("expires_at", models.DateTimeField(help_text="When this subscription expires")),
315
429
  (
316
- "last_billed",
317
- models.DateTimeField(blank=True, help_text="Last billing date", null=True),
430
+ "monthly_cost_usd",
431
+ models.FloatField(
432
+ default=0.0,
433
+ help_text="Monthly cost in USD",
434
+ validators=[django.core.validators.MinValueValidator(0.0)],
435
+ ),
318
436
  ),
319
437
  (
320
- "next_billing",
321
- models.DateTimeField(blank=True, help_text="Next billing date", null=True),
438
+ "total_requests",
439
+ models.PositiveIntegerField(
440
+ default=0, help_text="Total API requests made with this subscription"
441
+ ),
322
442
  ),
323
443
  (
324
- "expires_at",
444
+ "last_request_at",
325
445
  models.DateTimeField(
326
- blank=True, help_text="Subscription expiration", null=True
446
+ blank=True, help_text="When the last API request was made", null=True
327
447
  ),
328
448
  ),
329
449
  (
330
- "cancelled_at",
331
- models.DateTimeField(blank=True, help_text="Cancellation date", null=True),
332
- ),
333
- (
334
- "metadata",
335
- models.JSONField(default=dict, help_text="Additional subscription metadata"),
450
+ "auto_renew",
451
+ models.BooleanField(
452
+ default=False, help_text="Whether to automatically renew this subscription"
453
+ ),
336
454
  ),
337
455
  (
338
- "endpoint_group",
339
- models.ForeignKey(
340
- help_text="Endpoint group",
341
- on_delete=django.db.models.deletion.CASCADE,
456
+ "endpoint_groups",
457
+ models.ManyToManyField(
458
+ blank=True,
459
+ help_text="Endpoint groups accessible with this subscription",
342
460
  related_name="subscriptions",
343
- to="django_cfg_payments.endpointgroup",
461
+ to="payments.endpointgroup",
344
462
  ),
345
463
  ),
346
464
  (
347
465
  "user",
348
466
  models.ForeignKey(
349
- help_text="Subscriber",
467
+ help_text="User who owns this subscription",
350
468
  on_delete=django.db.models.deletion.CASCADE,
351
- related_name="subscriptions",
469
+ related_name="payment_subscriptions",
352
470
  to=settings.AUTH_USER_MODEL,
353
471
  ),
354
472
  ),
@@ -356,7 +474,7 @@ class Migration(migrations.Migration):
356
474
  options={
357
475
  "verbose_name": "Subscription",
358
476
  "verbose_name_plural": "Subscriptions",
359
- "db_table": "user_subscriptions",
477
+ "db_table": "payments_subscriptions",
360
478
  "ordering": ["-created_at"],
361
479
  },
362
480
  ),
@@ -369,38 +487,140 @@ class Migration(migrations.Migration):
369
487
  auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
370
488
  ),
371
489
  ),
372
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
373
- ("updated_at", models.DateTimeField(auto_now=True)),
374
- ("name", models.CharField(help_text="Tariff name", max_length=100, unique=True)),
375
490
  (
376
- "display_name",
377
- models.CharField(help_text="Human-readable tariff name", max_length=200),
491
+ "created_at",
492
+ models.DateTimeField(
493
+ auto_now_add=True, db_index=True, help_text="When this record was created"
494
+ ),
495
+ ),
496
+ (
497
+ "updated_at",
498
+ models.DateTimeField(
499
+ auto_now=True, help_text="When this record was last updated"
500
+ ),
501
+ ),
502
+ (
503
+ "name",
504
+ models.CharField(
505
+ help_text="Tariff name (e.g., 'Free', 'Basic', 'Pro')",
506
+ max_length=100,
507
+ unique=True,
508
+ ),
509
+ ),
510
+ (
511
+ "code",
512
+ models.CharField(
513
+ help_text="Tariff code (e.g., 'free', 'basic', 'pro')",
514
+ max_length=50,
515
+ unique=True,
516
+ ),
517
+ ),
518
+ (
519
+ "description",
520
+ models.TextField(
521
+ blank=True, help_text="Detailed description of what this tariff includes"
522
+ ),
378
523
  ),
379
- ("description", models.TextField(blank=True, help_text="Tariff description")),
380
524
  (
381
- "monthly_price",
525
+ "monthly_price_usd",
382
526
  models.FloatField(
383
- default=0.0,
384
527
  help_text="Monthly price in USD",
385
528
  validators=[django.core.validators.MinValueValidator(0.0)],
386
529
  ),
387
530
  ),
388
531
  (
389
- "request_limit",
532
+ "yearly_price_usd",
533
+ models.FloatField(
534
+ blank=True,
535
+ help_text="Yearly price in USD (optional discount)",
536
+ null=True,
537
+ validators=[django.core.validators.MinValueValidator(0.0)],
538
+ ),
539
+ ),
540
+ (
541
+ "requests_per_hour",
390
542
  models.PositiveIntegerField(
391
- default=1000, help_text="Monthly request limit (0 = unlimited)"
543
+ default=100,
544
+ help_text="API requests allowed per hour",
545
+ validators=[
546
+ django.core.validators.MinValueValidator(1),
547
+ django.core.validators.MaxValueValidator(100000),
548
+ ],
549
+ ),
550
+ ),
551
+ (
552
+ "requests_per_day",
553
+ models.PositiveIntegerField(
554
+ default=1000,
555
+ help_text="API requests allowed per day",
556
+ validators=[
557
+ django.core.validators.MinValueValidator(1),
558
+ django.core.validators.MaxValueValidator(1000000),
559
+ ],
560
+ ),
561
+ ),
562
+ (
563
+ "requests_per_month",
564
+ models.PositiveIntegerField(
565
+ default=30000,
566
+ help_text="API requests allowed per month",
567
+ validators=[
568
+ django.core.validators.MinValueValidator(1),
569
+ django.core.validators.MaxValueValidator(10000000),
570
+ ],
571
+ ),
572
+ ),
573
+ (
574
+ "max_api_keys",
575
+ models.PositiveIntegerField(
576
+ default=1,
577
+ help_text="Maximum number of API keys allowed",
578
+ validators=[
579
+ django.core.validators.MinValueValidator(1),
580
+ django.core.validators.MaxValueValidator(100),
581
+ ],
582
+ ),
583
+ ),
584
+ (
585
+ "supports_webhooks",
586
+ models.BooleanField(default=True, help_text="Whether webhooks are supported"),
587
+ ),
588
+ (
589
+ "priority_support",
590
+ models.BooleanField(
591
+ default=False, help_text="Whether priority support is included"
592
+ ),
593
+ ),
594
+ (
595
+ "is_active",
596
+ models.BooleanField(
597
+ default=True,
598
+ help_text="Whether this tariff is available for new subscriptions",
599
+ ),
600
+ ),
601
+ (
602
+ "is_public",
603
+ models.BooleanField(
604
+ default=True, help_text="Whether this tariff is publicly visible"
605
+ ),
606
+ ),
607
+ (
608
+ "sort_order",
609
+ models.PositiveIntegerField(
610
+ default=0, help_text="Sort order for display (lower numbers first)"
392
611
  ),
393
612
  ),
394
- ("is_active", models.BooleanField(default=True, help_text="Is this tariff active")),
395
613
  ],
396
614
  options={
397
615
  "verbose_name": "Tariff",
398
616
  "verbose_name_plural": "Tariffs",
399
- "db_table": "tariffs",
400
- "ordering": ["monthly_price"],
617
+ "db_table": "payments_tariffs",
618
+ "ordering": ["sort_order", "monthly_price_usd"],
401
619
  "indexes": [
402
- models.Index(fields=["is_active"], name="tariffs_is_acti_e0eeb6_idx"),
403
- models.Index(fields=["monthly_price"], name="tariffs_monthly_fc7022_idx"),
620
+ models.Index(
621
+ fields=["is_active", "is_public"], name="payments_ta_is_acti_716f1f_idx"
622
+ ),
623
+ models.Index(fields=["sort_order"], name="payments_ta_sort_or_e6ec28_idx"),
404
624
  ],
405
625
  },
406
626
  ),
@@ -413,233 +633,267 @@ class Migration(migrations.Migration):
413
633
  auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
414
634
  ),
415
635
  ),
416
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
417
- ("updated_at", models.DateTimeField(auto_now=True)),
636
+ (
637
+ "created_at",
638
+ models.DateTimeField(
639
+ auto_now_add=True, db_index=True, help_text="When this record was created"
640
+ ),
641
+ ),
642
+ (
643
+ "updated_at",
644
+ models.DateTimeField(
645
+ auto_now=True, help_text="When this record was last updated"
646
+ ),
647
+ ),
648
+ (
649
+ "custom_rate_limit",
650
+ models.PositiveIntegerField(
651
+ blank=True,
652
+ help_text="Custom rate limit for this endpoint group (overrides tariff default)",
653
+ null=True,
654
+ ),
655
+ ),
418
656
  (
419
657
  "is_enabled",
420
658
  models.BooleanField(
421
- default=True, help_text="Is this endpoint group enabled for this tariff"
659
+ default=True,
660
+ help_text="Whether this endpoint group is enabled for this tariff",
422
661
  ),
423
662
  ),
424
663
  (
425
664
  "endpoint_group",
426
665
  models.ForeignKey(
427
- help_text="Endpoint group",
428
666
  on_delete=django.db.models.deletion.CASCADE,
429
667
  related_name="tariffs",
430
- to="django_cfg_payments.endpointgroup",
668
+ to="payments.endpointgroup",
431
669
  ),
432
670
  ),
433
671
  (
434
672
  "tariff",
435
673
  models.ForeignKey(
436
- help_text="Tariff plan",
437
674
  on_delete=django.db.models.deletion.CASCADE,
438
675
  related_name="endpoint_groups",
439
- to="django_cfg_payments.tariff",
676
+ to="payments.tariff",
440
677
  ),
441
678
  ),
442
679
  ],
443
680
  options={
444
681
  "verbose_name": "Tariff Endpoint Group",
445
682
  "verbose_name_plural": "Tariff Endpoint Groups",
446
- "db_table": "tariff_endpoint_groups",
683
+ "db_table": "payments_tariff_endpoint_groups",
684
+ "ordering": ["tariff__sort_order", "endpoint_group__name"],
447
685
  },
448
686
  ),
449
687
  migrations.CreateModel(
450
- name="UniversalPayment",
688
+ name="Transaction",
451
689
  fields=[
452
690
  (
453
691
  "id",
454
692
  models.UUIDField(
455
693
  default=uuid.uuid4,
456
694
  editable=False,
457
- help_text="Unique identifier",
695
+ help_text="Unique identifier for this record",
458
696
  primary_key=True,
459
697
  serialize=False,
460
698
  ),
461
699
  ),
462
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
463
- ("updated_at", models.DateTimeField(auto_now=True)),
464
700
  (
465
- "amount_usd",
466
- models.FloatField(
467
- help_text="Payment amount in USD",
468
- validators=[django.core.validators.MinValueValidator(1.0)],
701
+ "created_at",
702
+ models.DateTimeField(
703
+ auto_now_add=True, db_index=True, help_text="When this record was created"
469
704
  ),
470
705
  ),
471
706
  (
472
- "currency_code",
473
- models.CharField(help_text="Currency used for payment", max_length=10),
474
- ),
475
- (
476
- "actual_amount_usd",
477
- models.FloatField(
478
- blank=True, help_text="Actual received amount in USD", null=True
707
+ "updated_at",
708
+ models.DateTimeField(
709
+ auto_now=True, help_text="When this record was last updated"
479
710
  ),
480
711
  ),
481
712
  (
482
- "actual_currency_code",
713
+ "transaction_type",
483
714
  models.CharField(
484
- blank=True, help_text="Actual received currency", max_length=10, null=True
715
+ choices=[
716
+ ("deposit", "Deposit"),
717
+ ("withdrawal", "Withdrawal"),
718
+ ("payment", "Payment"),
719
+ ("refund", "Refund"),
720
+ ("fee", "Fee"),
721
+ ("bonus", "Bonus"),
722
+ ("adjustment", "Adjustment"),
723
+ ],
724
+ help_text="Type of transaction",
725
+ max_length=20,
485
726
  ),
486
727
  ),
487
728
  (
488
- "fee_amount_usd",
729
+ "amount_usd",
489
730
  models.FloatField(
490
- blank=True,
491
- help_text="Fee amount in USD",
492
- null=True,
493
- validators=[django.core.validators.MinValueValidator(0.0)],
731
+ help_text="Transaction amount in USD (positive=credit, negative=debit)"
494
732
  ),
495
733
  ),
496
734
  (
497
- "provider",
498
- models.CharField(
499
- choices=[
500
- ("nowpayments", "NowPayments"),
501
- ("cryptapi", "CryptAPI"),
502
- ("cryptomus", "Cryptomus"),
503
- ("stripe", "Stripe"),
504
- ("internal", "Internal"),
505
- ],
506
- help_text="Payment provider",
507
- max_length=50,
735
+ "balance_after",
736
+ models.FloatField(
737
+ help_text="User balance after this transaction",
738
+ validators=[django.core.validators.MinValueValidator(0.0)],
508
739
  ),
509
740
  ),
510
741
  (
511
- "status",
742
+ "payment_id",
512
743
  models.CharField(
513
- choices=[
514
- ("pending", "Pending"),
515
- ("confirming", "Confirming"),
516
- ("confirmed", "Confirmed"),
517
- ("completed", "Completed"),
518
- ("failed", "Failed"),
519
- ("expired", "Expired"),
520
- ("cancelled", "Cancelled"),
521
- ("refunded", "Refunded"),
522
- ],
523
- default="pending",
524
- help_text="Payment status",
525
- max_length=20,
744
+ blank=True,
745
+ db_index=True,
746
+ help_text="Related payment ID (if applicable)",
747
+ max_length=100,
748
+ null=True,
526
749
  ),
527
750
  ),
751
+ ("description", models.TextField(help_text="Transaction description")),
528
752
  (
529
- "provider_payment_id",
530
- models.CharField(
531
- blank=True,
532
- help_text="Provider's payment ID",
533
- max_length=255,
534
- null=True,
535
- unique=True,
753
+ "metadata",
754
+ models.JSONField(
755
+ blank=True, default=dict, help_text="Additional transaction metadata"
536
756
  ),
537
757
  ),
538
758
  (
539
- "internal_payment_id",
540
- models.CharField(
541
- help_text="Internal payment identifier", max_length=100, unique=True
759
+ "user",
760
+ models.ForeignKey(
761
+ help_text="User who owns this transaction",
762
+ on_delete=django.db.models.deletion.CASCADE,
763
+ related_name="payment_transactions",
764
+ to=settings.AUTH_USER_MODEL,
542
765
  ),
543
766
  ),
767
+ ],
768
+ options={
769
+ "verbose_name": "Transaction",
770
+ "verbose_name_plural": "Transactions",
771
+ "db_table": "payments_transactions",
772
+ "ordering": ["-created_at"],
773
+ },
774
+ ),
775
+ migrations.CreateModel(
776
+ name="UniversalPayment",
777
+ fields=[
544
778
  (
545
- "pay_address",
546
- models.CharField(
547
- blank=True,
548
- help_text="Cryptocurrency payment address",
549
- max_length=200,
550
- null=True,
779
+ "id",
780
+ models.UUIDField(
781
+ default=uuid.uuid4,
782
+ editable=False,
783
+ help_text="Unique identifier for this record",
784
+ primary_key=True,
785
+ serialize=False,
551
786
  ),
552
787
  ),
553
788
  (
554
- "pay_amount",
555
- models.FloatField(
556
- blank=True, help_text="Amount to pay in cryptocurrency", null=True
789
+ "created_at",
790
+ models.DateTimeField(
791
+ auto_now_add=True, db_index=True, help_text="When this record was created"
557
792
  ),
558
793
  ),
559
794
  (
560
- "network",
561
- models.CharField(
562
- blank=True,
563
- help_text="Blockchain network (mainnet, testnet, etc.)",
564
- max_length=50,
565
- null=True,
795
+ "updated_at",
796
+ models.DateTimeField(
797
+ auto_now=True, help_text="When this record was last updated"
566
798
  ),
567
799
  ),
568
- ("description", models.TextField(blank=True, help_text="Payment description")),
569
800
  (
570
- "order_id",
801
+ "internal_payment_id",
571
802
  models.CharField(
572
- blank=True, help_text="Order reference ID", max_length=255, null=True
803
+ db_index=True,
804
+ help_text="Internal payment identifier",
805
+ max_length=100,
806
+ unique=True,
573
807
  ),
574
808
  ),
575
- ("metadata", models.JSONField(default=dict, help_text="Additional metadata")),
576
809
  (
577
- "webhook_data",
578
- models.JSONField(
579
- blank=True, help_text="Raw webhook data from provider", null=True
810
+ "amount_usd",
811
+ models.FloatField(
812
+ help_text="Payment amount in USD (float for performance)",
813
+ validators=[
814
+ django.core.validators.MinValueValidator(1.0),
815
+ django.core.validators.MaxValueValidator(50000.0),
816
+ ],
580
817
  ),
581
818
  ),
582
819
  (
583
- "security_nonce",
584
- models.CharField(
820
+ "pay_amount",
821
+ models.DecimalField(
585
822
  blank=True,
586
- db_index=True,
587
- help_text="Security nonce for replay attack protection (CryptAPI, Cryptomus, etc.)",
588
- max_length=64,
823
+ decimal_places=8,
824
+ help_text="Amount to pay in cryptocurrency (Decimal for precision)",
825
+ max_digits=20,
589
826
  null=True,
590
827
  ),
591
828
  ),
592
829
  (
593
- "provider_callback_url",
594
- models.CharField(
595
- blank=True,
596
- help_text="Full callback URL with security parameters",
597
- max_length=512,
598
- null=True,
830
+ "actual_amount_usd",
831
+ models.FloatField(
832
+ blank=True, help_text="Actual amount received in USD", null=True
599
833
  ),
600
834
  ),
601
835
  (
602
- "transaction_hash",
836
+ "fee_amount_usd",
837
+ models.FloatField(blank=True, help_text="Fee amount in USD", null=True),
838
+ ),
839
+ (
840
+ "provider",
603
841
  models.CharField(
604
- blank=True,
605
- db_index=True,
606
- help_text="Main transaction hash/ID (txid_in for CryptAPI, hash for Cryptomus)",
607
- max_length=256,
608
- null=True,
842
+ choices=[("nowpayments", "NowPayments")],
843
+ default="nowpayments",
844
+ help_text="Payment provider",
845
+ max_length=50,
609
846
  ),
610
847
  ),
611
848
  (
612
- "confirmation_hash",
849
+ "provider_payment_id",
613
850
  models.CharField(
614
851
  blank=True,
615
- help_text="Secondary transaction hash (txid_out for CryptAPI, confirmation for others)",
616
- max_length=256,
852
+ db_index=True,
853
+ help_text="Provider's payment ID",
854
+ max_length=255,
617
855
  null=True,
618
856
  ),
619
857
  ),
620
858
  (
621
- "sender_address",
859
+ "status",
622
860
  models.CharField(
623
- blank=True,
624
- help_text="Sender address (address_in for CryptAPI, from_address for Cryptomus)",
625
- max_length=200,
626
- null=True,
861
+ choices=[
862
+ ("pending", "Pending"),
863
+ ("confirming", "Confirming"),
864
+ ("confirmed", "Confirmed"),
865
+ ("completed", "Completed"),
866
+ ("failed", "Failed"),
867
+ ("expired", "Expired"),
868
+ ("cancelled", "Cancelled"),
869
+ ("refunded", "Refunded"),
870
+ ],
871
+ db_index=True,
872
+ default="pending",
873
+ help_text="Current payment status",
874
+ max_length=20,
627
875
  ),
628
876
  ),
629
877
  (
630
- "receiver_address",
878
+ "pay_address",
631
879
  models.CharField(
632
880
  blank=True,
633
- help_text="Receiver address (address_out for CryptAPI, to_address for Cryptomus)",
634
- max_length=200,
881
+ help_text="Cryptocurrency payment address",
882
+ max_length=255,
635
883
  null=True,
636
884
  ),
637
885
  ),
638
886
  (
639
- "crypto_amount",
640
- models.FloatField(
887
+ "payment_url",
888
+ models.URLField(blank=True, help_text="Payment page URL", null=True),
889
+ ),
890
+ (
891
+ "transaction_hash",
892
+ models.CharField(
641
893
  blank=True,
642
- help_text="Amount in cryptocurrency units (value_coin for CryptAPI, amount for Cryptomus)",
894
+ db_index=True,
895
+ help_text="Blockchain transaction hash",
896
+ max_length=256,
643
897
  null=True,
644
898
  ),
645
899
  ),
@@ -650,139 +904,84 @@ class Migration(migrations.Migration):
650
904
  ),
651
905
  ),
652
906
  (
653
- "expires_at",
654
- models.DateTimeField(
655
- blank=True, help_text="Payment expiration time", null=True
907
+ "security_nonce",
908
+ models.CharField(
909
+ blank=True,
910
+ db_index=True,
911
+ help_text="Security nonce for validation",
912
+ max_length=64,
913
+ null=True,
656
914
  ),
657
915
  ),
658
916
  (
659
- "completed_at",
917
+ "expires_at",
660
918
  models.DateTimeField(
661
- blank=True, help_text="Payment completion time", null=True
919
+ blank=True, help_text="When this payment expires", null=True
662
920
  ),
663
921
  ),
664
922
  (
665
- "processed_at",
923
+ "completed_at",
666
924
  models.DateTimeField(
667
- blank=True,
668
- help_text="When the payment was processed and funds added to balance",
669
- null=True,
925
+ blank=True, help_text="When this payment was completed", null=True
670
926
  ),
671
927
  ),
928
+ ("description", models.TextField(blank=True, help_text="Payment description")),
672
929
  (
673
- "user",
674
- models.ForeignKey(
675
- help_text="User who initiated this payment",
676
- on_delete=django.db.models.deletion.CASCADE,
677
- related_name="universal_payments",
678
- to=settings.AUTH_USER_MODEL,
679
- ),
930
+ "callback_url",
931
+ models.URLField(blank=True, help_text="Success callback URL", null=True),
680
932
  ),
681
- ],
682
- options={
683
- "verbose_name": "Universal Payment",
684
- "verbose_name_plural": "Universal Payments",
685
- "db_table": "universal_payments",
686
- "ordering": ["-created_at"],
687
- },
688
- ),
689
- migrations.CreateModel(
690
- name="Transaction",
691
- fields=[
692
933
  (
693
- "id",
694
- models.UUIDField(
695
- default=uuid.uuid4,
696
- editable=False,
697
- help_text="Unique identifier",
698
- primary_key=True,
699
- serialize=False,
700
- ),
934
+ "cancel_url",
935
+ models.URLField(blank=True, help_text="Cancellation URL", null=True),
701
936
  ),
702
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
703
- ("updated_at", models.DateTimeField(auto_now=True)),
704
937
  (
705
- "amount_usd",
706
- models.FloatField(
707
- help_text="Transaction amount in USD (positive for credits, negative for debits)"
938
+ "provider_data",
939
+ models.JSONField(
940
+ blank=True,
941
+ default=dict,
942
+ help_text="Provider-specific data (validated by Pydantic)",
708
943
  ),
709
944
  ),
710
945
  (
711
- "transaction_type",
712
- models.CharField(
713
- choices=[
714
- ("payment", "Payment"),
715
- ("subscription", "Subscription"),
716
- ("refund", "Refund"),
717
- ("credit", "Credit"),
718
- ("debit", "Debit"),
719
- ("hold", "Hold"),
720
- ("release", "Release"),
721
- ("fee", "Fee"),
722
- ("adjustment", "Adjustment"),
723
- ],
724
- help_text="Type of transaction",
725
- max_length=20,
946
+ "webhook_data",
947
+ models.JSONField(
948
+ blank=True, default=dict, help_text="Webhook data (validated by Pydantic)"
726
949
  ),
727
950
  ),
728
951
  (
729
- "description",
730
- models.TextField(help_text="Human-readable description of the transaction"),
731
- ),
732
- (
733
- "balance_before",
734
- models.FloatField(help_text="User balance before this transaction"),
735
- ),
736
- (
737
- "balance_after",
738
- models.FloatField(help_text="User balance after this transaction"),
739
- ),
740
- (
741
- "reference_id",
742
- models.CharField(
743
- blank=True, help_text="External reference ID", max_length=255, null=True
952
+ "currency",
953
+ models.ForeignKey(
954
+ help_text="Payment currency",
955
+ on_delete=django.db.models.deletion.PROTECT,
956
+ related_name="payments",
957
+ to="payments.currency",
744
958
  ),
745
959
  ),
746
960
  (
747
- "metadata",
748
- models.JSONField(default=dict, help_text="Additional transaction metadata"),
749
- ),
750
- (
751
- "subscription",
961
+ "network",
752
962
  models.ForeignKey(
753
963
  blank=True,
754
- help_text="Related subscription (if applicable)",
964
+ help_text="Blockchain network (for crypto payments)",
755
965
  null=True,
756
- on_delete=django.db.models.deletion.SET_NULL,
757
- related_name="transactions",
758
- to="django_cfg_payments.subscription",
966
+ on_delete=django.db.models.deletion.PROTECT,
967
+ related_name="payments",
968
+ to="payments.network",
759
969
  ),
760
970
  ),
761
971
  (
762
972
  "user",
763
973
  models.ForeignKey(
764
- help_text="User who made this transaction",
974
+ help_text="User who created this payment",
765
975
  on_delete=django.db.models.deletion.CASCADE,
766
- related_name="transactions",
976
+ related_name="payments",
767
977
  to=settings.AUTH_USER_MODEL,
768
978
  ),
769
979
  ),
770
- (
771
- "payment",
772
- models.ForeignKey(
773
- blank=True,
774
- help_text="Related payment (if applicable)",
775
- null=True,
776
- on_delete=django.db.models.deletion.SET_NULL,
777
- related_name="transactions",
778
- to="django_cfg_payments.universalpayment",
779
- ),
780
- ),
781
980
  ],
782
981
  options={
783
- "verbose_name": "Transaction",
784
- "verbose_name_plural": "Transactions",
785
- "db_table": "user_transactions",
982
+ "verbose_name": "Universal Payment",
983
+ "verbose_name_plural": "Universal Payments",
984
+ "db_table": "payments_universal",
786
985
  "ordering": ["-created_at"],
787
986
  },
788
987
  ),
@@ -795,29 +994,19 @@ class Migration(migrations.Migration):
795
994
  auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
796
995
  ),
797
996
  ),
798
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
799
- ("updated_at", models.DateTimeField(auto_now=True)),
800
- (
801
- "amount_usd",
802
- models.FloatField(
803
- default=0.0,
804
- help_text="Current balance in USD",
805
- validators=[django.core.validators.MinValueValidator(0.0)],
806
- ),
807
- ),
808
997
  (
809
- "reserved_usd",
998
+ "balance_usd",
810
999
  models.FloatField(
811
1000
  default=0.0,
812
- help_text="Reserved balance in USD (for pending transactions)",
1001
+ help_text="Current balance in USD (float for performance)",
813
1002
  validators=[django.core.validators.MinValueValidator(0.0)],
814
1003
  ),
815
1004
  ),
816
1005
  (
817
- "total_earned",
1006
+ "total_deposited",
818
1007
  models.FloatField(
819
1008
  default=0.0,
820
- help_text="Total amount earned (lifetime)",
1009
+ help_text="Total amount deposited (lifetime)",
821
1010
  validators=[django.core.validators.MinValueValidator(0.0)],
822
1011
  ),
823
1012
  ),
@@ -835,12 +1024,14 @@ class Migration(migrations.Migration):
835
1024
  blank=True, help_text="When the last transaction occurred", null=True
836
1025
  ),
837
1026
  ),
1027
+ ("created_at", models.DateTimeField(auto_now_add=True)),
1028
+ ("updated_at", models.DateTimeField(auto_now=True)),
838
1029
  (
839
1030
  "user",
840
1031
  models.OneToOneField(
841
1032
  help_text="User who owns this balance",
842
1033
  on_delete=django.db.models.deletion.CASCADE,
843
- related_name="balance",
1034
+ related_name="payment_balance",
844
1035
  to=settings.AUTH_USER_MODEL,
845
1036
  ),
846
1037
  ),
@@ -848,7 +1039,7 @@ class Migration(migrations.Migration):
848
1039
  options={
849
1040
  "verbose_name": "User Balance",
850
1041
  "verbose_name_plural": "User Balances",
851
- "db_table": "user_balances",
1042
+ "db_table": "payments_user_balances",
852
1043
  },
853
1044
  ),
854
1045
  migrations.CreateModel(
@@ -859,238 +1050,219 @@ class Migration(migrations.Migration):
859
1050
  models.UUIDField(
860
1051
  default=uuid.uuid4,
861
1052
  editable=False,
862
- help_text="Unique identifier",
1053
+ help_text="Unique identifier for this record",
863
1054
  primary_key=True,
864
1055
  serialize=False,
865
1056
  ),
866
1057
  ),
867
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
868
- ("updated_at", models.DateTimeField(auto_now=True)),
869
- ("name", models.CharField(help_text="Human-readable key name", max_length=100)),
870
1058
  (
871
- "key_value",
872
- models.CharField(
873
- help_text="API key value (plain text)", max_length=255, unique=True
1059
+ "created_at",
1060
+ models.DateTimeField(
1061
+ auto_now_add=True, db_index=True, help_text="When this record was created"
874
1062
  ),
875
1063
  ),
876
1064
  (
877
- "key_prefix",
878
- models.CharField(help_text="Key prefix for identification", max_length=20),
1065
+ "updated_at",
1066
+ models.DateTimeField(
1067
+ auto_now=True, help_text="When this record was last updated"
1068
+ ),
879
1069
  ),
880
- ("is_active", models.BooleanField(default=True, help_text="Is key active")),
881
1070
  (
882
- "last_used",
883
- models.DateTimeField(blank=True, help_text="Last usage timestamp", null=True),
1071
+ "name",
1072
+ models.CharField(
1073
+ help_text="Human-readable name for this API key", max_length=100
1074
+ ),
884
1075
  ),
885
1076
  (
886
- "usage_count",
887
- models.PositiveBigIntegerField(default=0, help_text="Total usage count"),
1077
+ "key",
1078
+ models.CharField(
1079
+ help_text="The actual API key (auto-generated)",
1080
+ max_length=64,
1081
+ unique=True,
1082
+ validators=[django.core.validators.MinLengthValidator(32)],
1083
+ ),
888
1084
  ),
889
1085
  (
890
- "expires_at",
891
- models.DateTimeField(blank=True, help_text="Key expiration", null=True),
1086
+ "is_active",
1087
+ models.BooleanField(default=True, help_text="Whether this API key is active"),
892
1088
  ),
893
1089
  (
894
- "user",
895
- models.ForeignKey(
896
- help_text="API key owner",
897
- on_delete=django.db.models.deletion.CASCADE,
898
- related_name="api_keys",
899
- to=settings.AUTH_USER_MODEL,
1090
+ "total_requests",
1091
+ models.PositiveIntegerField(
1092
+ default=0, help_text="Total number of requests made with this key"
900
1093
  ),
901
1094
  ),
902
- ],
903
- options={
904
- "verbose_name": "API Key",
905
- "verbose_name_plural": "API Keys",
906
- "db_table": "api_keys",
907
- "ordering": ["-created_at"],
908
- "indexes": [
909
- models.Index(fields=["user", "is_active"], name="api_keys_user_id_6e7352_idx"),
910
- models.Index(fields=["key_value"], name="api_keys_key_val_a809c4_idx"),
911
- models.Index(fields=["key_prefix"], name="api_keys_key_pre_9c2634_idx"),
912
- models.Index(fields=["last_used"], name="api_keys_last_us_f1be76_idx"),
913
- models.Index(fields=["expires_at"], name="api_keys_expires_f68b1a_idx"),
914
- ],
915
- },
916
- ),
917
- migrations.CreateModel(
918
- name="CurrencyNetwork",
919
- fields=[
920
1095
  (
921
- "id",
922
- models.BigAutoField(
923
- auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
1096
+ "last_used_at",
1097
+ models.DateTimeField(
1098
+ blank=True, help_text="When this API key was last used", null=True
924
1099
  ),
925
1100
  ),
926
- ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)),
927
- ("updated_at", models.DateTimeField(auto_now=True)),
928
1101
  (
929
- "network_name",
930
- models.CharField(
931
- help_text="Network name (e.g., mainnet, polygon, bsc)", max_length=50
1102
+ "expires_at",
1103
+ models.DateTimeField(
1104
+ blank=True,
1105
+ help_text="When this API key expires (null = never expires)",
1106
+ null=True,
932
1107
  ),
933
1108
  ),
934
1109
  (
935
- "network_code",
936
- models.CharField(help_text="Network code for API integration", max_length=20),
937
- ),
938
- (
939
- "is_active",
940
- models.BooleanField(default=True, help_text="Whether this network is active"),
941
- ),
942
- (
943
- "confirmation_blocks",
944
- models.PositiveIntegerField(
945
- default=1, help_text="Number of confirmations required"
1110
+ "allowed_ips",
1111
+ models.TextField(
1112
+ blank=True,
1113
+ help_text="Comma-separated list of allowed IP addresses (empty = any IP)",
946
1114
  ),
947
1115
  ),
948
1116
  (
949
- "currency",
1117
+ "user",
950
1118
  models.ForeignKey(
951
- help_text="Currency this network supports",
1119
+ help_text="User who owns this API key",
952
1120
  on_delete=django.db.models.deletion.CASCADE,
953
- related_name="networks",
954
- to="django_cfg_payments.currency",
1121
+ related_name="api_keys",
1122
+ to=settings.AUTH_USER_MODEL,
955
1123
  ),
956
1124
  ),
957
1125
  ],
958
1126
  options={
959
- "verbose_name": "Currency Network",
960
- "verbose_name_plural": "Currency Networks",
961
- "db_table": "payment_currency_networks",
1127
+ "verbose_name": "API Key",
1128
+ "verbose_name_plural": "API Keys",
1129
+ "db_table": "payments_api_keys",
1130
+ "ordering": ["-created_at"],
962
1131
  "indexes": [
1132
+ models.Index(fields=["key"], name="payments_ap_key_9290c6_idx"),
963
1133
  models.Index(
964
- fields=["currency", "is_active"], name="payment_cur_currenc_8709aa_idx"
1134
+ fields=["user", "is_active"], name="payments_ap_user_id_784de9_idx"
965
1135
  ),
966
- models.Index(fields=["network_code"], name="payment_cur_network_597115_idx"),
1136
+ models.Index(fields=["expires_at"], name="payments_ap_expires_dff82d_idx"),
967
1137
  ],
968
- "unique_together": {("currency", "network_code")},
969
1138
  },
970
1139
  ),
971
1140
  migrations.AddIndex(
972
- model_name="subscription",
973
- index=models.Index(fields=["user", "status"], name="user_subscr_user_id_c57286_idx"),
1141
+ model_name="network",
1142
+ index=models.Index(fields=["is_active"], name="payments_ne_is_acti_915889_idx"),
974
1143
  ),
975
1144
  migrations.AddIndex(
976
- model_name="subscription",
1145
+ model_name="network",
1146
+ index=models.Index(fields=["code"], name="payments_ne_code_28d2a9_idx"),
1147
+ ),
1148
+ migrations.AddIndex(
1149
+ model_name="providercurrency",
977
1150
  index=models.Index(
978
- fields=["endpoint_group", "status"], name="user_subscr_endpoin_12e673_idx"
1151
+ fields=["provider", "is_enabled"], name="payments_pr_provide_585c03_idx"
979
1152
  ),
980
1153
  ),
981
1154
  migrations.AddIndex(
982
- model_name="subscription",
1155
+ model_name="providercurrency",
983
1156
  index=models.Index(
984
- fields=["status", "expires_at"], name="user_subscr_status_e7170d_idx"
1157
+ fields=["currency", "is_enabled"], name="payments_pr_currenc_a88055_idx"
985
1158
  ),
986
1159
  ),
1160
+ migrations.AlterUniqueTogether(
1161
+ name="providercurrency",
1162
+ unique_together={("provider", "currency", "network")},
1163
+ ),
1164
+ migrations.AddIndex(
1165
+ model_name="subscription",
1166
+ index=models.Index(fields=["user", "status"], name="payments_su_user_id_3279a3_idx"),
1167
+ ),
987
1168
  migrations.AddIndex(
988
1169
  model_name="subscription",
989
- index=models.Index(fields=["next_billing"], name="user_subscr_next_bi_d8c922_idx"),
1170
+ index=models.Index(
1171
+ fields=["status", "expires_at"], name="payments_su_status_1a9788_idx"
1172
+ ),
990
1173
  ),
991
1174
  migrations.AddIndex(
992
1175
  model_name="subscription",
993
- index=models.Index(fields=["created_at"], name="user_subscr_created_fe5591_idx"),
1176
+ index=models.Index(fields=["tier", "status"], name="payments_su_tier_2ba72c_idx"),
994
1177
  ),
995
- migrations.AlterUniqueTogether(
996
- name="subscription",
997
- unique_together={("user", "endpoint_group")},
1178
+ migrations.AddConstraint(
1179
+ model_name="subscription",
1180
+ constraint=models.UniqueConstraint(
1181
+ condition=models.Q(("status", "active")),
1182
+ fields=("user",),
1183
+ name="one_active_subscription_per_user",
1184
+ ),
998
1185
  ),
999
1186
  migrations.AlterUniqueTogether(
1000
1187
  name="tariffendpointgroup",
1001
1188
  unique_together={("tariff", "endpoint_group")},
1002
1189
  ),
1003
1190
  migrations.AddIndex(
1004
- model_name="universalpayment",
1005
- index=models.Index(fields=["user", "status"], name="universal_p_user_id_7bdba2_idx"),
1006
- ),
1007
- migrations.AddIndex(
1008
- model_name="universalpayment",
1191
+ model_name="transaction",
1009
1192
  index=models.Index(
1010
- fields=["provider_payment_id"], name="universal_p_provide_bdcb09_idx"
1193
+ fields=["user", "created_at"], name="payments_tr_user_id_c1c1f7_idx"
1011
1194
  ),
1012
1195
  ),
1013
1196
  migrations.AddIndex(
1014
- model_name="universalpayment",
1197
+ model_name="transaction",
1015
1198
  index=models.Index(
1016
- fields=["internal_payment_id"], name="universal_p_interna_371bac_idx"
1199
+ fields=["transaction_type", "created_at"], name="payments_tr_transac_4c7d58_idx"
1017
1200
  ),
1018
1201
  ),
1019
1202
  migrations.AddIndex(
1020
- model_name="universalpayment",
1021
- index=models.Index(fields=["status"], name="universal_p_status_e531bf_idx"),
1022
- ),
1023
- migrations.AddIndex(
1024
- model_name="universalpayment",
1025
- index=models.Index(fields=["provider"], name="universal_p_provide_9820af_idx"),
1026
- ),
1027
- migrations.AddIndex(
1028
- model_name="universalpayment",
1029
- index=models.Index(fields=["currency_code"], name="universal_p_currenc_56f1fc_idx"),
1030
- ),
1031
- migrations.AddIndex(
1032
- model_name="universalpayment",
1033
- index=models.Index(fields=["created_at"], name="universal_p_created_978509_idx"),
1034
- ),
1035
- migrations.AddIndex(
1036
- model_name="universalpayment",
1037
- index=models.Index(fields=["processed_at"], name="universal_p_process_1c8a1f_idx"),
1203
+ model_name="transaction",
1204
+ index=models.Index(fields=["payment_id"], name="payments_tr_payment_96b00a_idx"),
1038
1205
  ),
1039
1206
  migrations.AddIndex(
1040
- model_name="universalpayment",
1041
- index=models.Index(fields=["security_nonce"], name="universal_p_securit_4a38cc_idx"),
1207
+ model_name="transaction",
1208
+ index=models.Index(fields=["amount_usd"], name="payments_tr_amount__c7f348_idx"),
1042
1209
  ),
1043
1210
  migrations.AddIndex(
1044
1211
  model_name="universalpayment",
1045
- index=models.Index(fields=["transaction_hash"], name="universal_p_transac_8a27c6_idx"),
1212
+ index=models.Index(fields=["user", "status"], name="payments_un_user_id_8ce187_idx"),
1046
1213
  ),
1047
1214
  migrations.AddIndex(
1048
1215
  model_name="universalpayment",
1049
1216
  index=models.Index(
1050
- fields=["confirmations_count"], name="universal_p_confirm_8df8c9_idx"
1217
+ fields=["provider", "status"], name="payments_un_provide_904e1a_idx"
1051
1218
  ),
1052
1219
  ),
1053
1220
  migrations.AddIndex(
1054
1221
  model_name="universalpayment",
1055
1222
  index=models.Index(
1056
- fields=["provider", "status", "confirmations_count"],
1057
- name="universal_p_provide_3c8a34_idx",
1223
+ fields=["status", "created_at"], name="payments_un_status_fd808c_idx"
1058
1224
  ),
1059
1225
  ),
1060
1226
  migrations.AddIndex(
1061
- model_name="transaction",
1227
+ model_name="universalpayment",
1062
1228
  index=models.Index(
1063
- fields=["user", "created_at"], name="user_transa_user_id_63659d_idx"
1229
+ fields=["provider_payment_id"], name="payments_un_provide_553809_idx"
1064
1230
  ),
1065
1231
  ),
1066
1232
  migrations.AddIndex(
1067
- model_name="transaction",
1068
- index=models.Index(fields=["transaction_type"], name="user_transa_transac_dc0ae2_idx"),
1233
+ model_name="universalpayment",
1234
+ index=models.Index(fields=["transaction_hash"], name="payments_un_transac_5a0fe3_idx"),
1069
1235
  ),
1070
1236
  migrations.AddIndex(
1071
- model_name="transaction",
1072
- index=models.Index(fields=["amount_usd"], name="user_transa_amount__2eeba2_idx"),
1237
+ model_name="universalpayment",
1238
+ index=models.Index(fields=["expires_at"], name="payments_un_expires_3b92ad_idx"),
1073
1239
  ),
1074
- migrations.AddIndex(
1075
- model_name="transaction",
1076
- index=models.Index(fields=["created_at"], name="user_transa_created_1cb93d_idx"),
1240
+ migrations.AddConstraint(
1241
+ model_name="universalpayment",
1242
+ constraint=models.CheckConstraint(
1243
+ condition=models.Q(("amount_usd__gte", 1.0)), name="payments_min_amount_check"
1244
+ ),
1077
1245
  ),
1078
- migrations.AddIndex(
1079
- model_name="transaction",
1080
- index=models.Index(fields=["reference_id"], name="user_transa_referen_c8e19f_idx"),
1246
+ migrations.AddConstraint(
1247
+ model_name="universalpayment",
1248
+ constraint=models.CheckConstraint(
1249
+ condition=models.Q(("amount_usd__lte", 50000.0)), name="payments_max_amount_check"
1250
+ ),
1081
1251
  ),
1082
1252
  migrations.AddIndex(
1083
1253
  model_name="userbalance",
1084
- index=models.Index(fields=["user"], name="user_balanc_user_id_9eea44_idx"),
1254
+ index=models.Index(fields=["balance_usd"], name="payments_us_balance_32e5aa_idx"),
1085
1255
  ),
1086
1256
  migrations.AddIndex(
1087
1257
  model_name="userbalance",
1088
- index=models.Index(fields=["amount_usd"], name="user_balanc_amount__6ff57b_idx"),
1258
+ index=models.Index(
1259
+ fields=["last_transaction_at"], name="payments_us_last_tr_935db2_idx"
1260
+ ),
1089
1261
  ),
1090
- migrations.AddIndex(
1262
+ migrations.AddConstraint(
1091
1263
  model_name="userbalance",
1092
- index=models.Index(
1093
- fields=["last_transaction_at"], name="user_balanc_last_tr_e5d8ae_idx"
1264
+ constraint=models.CheckConstraint(
1265
+ condition=models.Q(("balance_usd__gte", 0.0)), name="balance_non_negative_check"
1094
1266
  ),
1095
1267
  ),
1096
1268
  ]