django-cfg 1.2.31__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 (256) 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/manage_currencies.py +303 -151
  39. django_cfg/apps/payments/management/commands/manage_providers.py +333 -160
  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 +342 -152
  43. django_cfg/apps/payments/middleware/usage_tracking.py +249 -240
  44. django_cfg/apps/payments/migrations/0001_initial.py +708 -536
  45. django_cfg/apps/payments/models/__init__.py +13 -18
  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 +172 -148
  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 -285
  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 +346 -467
  67. django_cfg/apps/payments/services/core/subscription_service.py +425 -481
  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 +234 -174
  74. django_cfg/apps/payments/services/providers/nowpayments.py +478 -0
  75. django_cfg/apps/payments/services/providers/registry.py +367 -301
  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 +210 -129
  83. django_cfg/apps/payments/signals/balance_signals.py +174 -0
  84. django_cfg/apps/payments/signals/payment_signals.py +128 -103
  85. django_cfg/apps/payments/signals/subscription_signals.py +194 -142
  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 +45 -48
  93. django_cfg/apps/payments/urls_admin.py +33 -42
  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/config.py +1 -1
  110. django_cfg/core/config.py +40 -4
  111. django_cfg/core/generation.py +25 -4
  112. django_cfg/core/integration/README.md +363 -0
  113. django_cfg/core/integration/__init__.py +47 -0
  114. django_cfg/core/integration/commands_collector.py +239 -0
  115. django_cfg/core/integration/display/__init__.py +15 -0
  116. django_cfg/core/integration/display/base.py +157 -0
  117. django_cfg/core/integration/display/ngrok.py +164 -0
  118. django_cfg/core/integration/display/startup.py +815 -0
  119. django_cfg/core/integration/url_integration.py +123 -0
  120. django_cfg/core/integration/version_checker.py +160 -0
  121. django_cfg/management/commands/auto_generate.py +4 -0
  122. django_cfg/management/commands/check_settings.py +6 -0
  123. django_cfg/management/commands/clear_constance.py +5 -2
  124. django_cfg/management/commands/create_token.py +6 -0
  125. django_cfg/management/commands/list_urls.py +6 -0
  126. django_cfg/management/commands/migrate_all.py +6 -0
  127. django_cfg/management/commands/migrator.py +3 -0
  128. django_cfg/management/commands/rundramatiq.py +6 -0
  129. django_cfg/management/commands/runserver_ngrok.py +51 -29
  130. django_cfg/management/commands/script.py +6 -0
  131. django_cfg/management/commands/show_config.py +12 -2
  132. django_cfg/management/commands/show_urls.py +4 -0
  133. django_cfg/management/commands/superuser.py +6 -0
  134. django_cfg/management/commands/task_clear.py +4 -1
  135. django_cfg/management/commands/task_status.py +3 -1
  136. django_cfg/management/commands/test_email.py +3 -0
  137. django_cfg/management/commands/test_telegram.py +6 -0
  138. django_cfg/management/commands/test_twilio.py +6 -0
  139. django_cfg/management/commands/tree.py +6 -0
  140. django_cfg/management/commands/validate_config.py +155 -149
  141. django_cfg/models/constance.py +31 -11
  142. django_cfg/models/payments.py +175 -492
  143. django_cfg/modules/django_logger.py +160 -146
  144. django_cfg/modules/django_unfold/dashboard.py +64 -16
  145. django_cfg/registry/core.py +1 -0
  146. django_cfg/template_archive/django_sample.zip +0 -0
  147. django_cfg/utils/smart_defaults.py +222 -571
  148. django_cfg/utils/toolkit.py +51 -11
  149. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/METADATA +4 -1
  150. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/RECORD +153 -185
  151. django_cfg/apps/payments/__init__.py +0 -8
  152. django_cfg/apps/payments/admin/tariffs_admin.py +0 -199
  153. django_cfg/apps/payments/config/module.py +0 -70
  154. django_cfg/apps/payments/config/providers.py +0 -105
  155. django_cfg/apps/payments/config/settings.py +0 -96
  156. django_cfg/apps/payments/config/utils.py +0 -52
  157. django_cfg/apps/payments/decorators.py +0 -291
  158. django_cfg/apps/payments/management/commands/README.md +0 -146
  159. django_cfg/apps/payments/management/commands/currency_stats.py +0 -304
  160. django_cfg/apps/payments/managers/__init__.py +0 -23
  161. django_cfg/apps/payments/managers/api_key_manager.py +0 -35
  162. django_cfg/apps/payments/managers/balance_manager.py +0 -361
  163. django_cfg/apps/payments/managers/currency_manager.py +0 -306
  164. django_cfg/apps/payments/managers/payment_manager.py +0 -192
  165. django_cfg/apps/payments/managers/subscription_manager.py +0 -37
  166. django_cfg/apps/payments/managers/tariff_manager.py +0 -29
  167. django_cfg/apps/payments/migrations/0002_network_providercurrency_and_more.py +0 -241
  168. django_cfg/apps/payments/migrations/0003_add_usd_rate_cache.py +0 -30
  169. django_cfg/apps/payments/models/events.py +0 -73
  170. django_cfg/apps/payments/serializers/__init__.py +0 -57
  171. django_cfg/apps/payments/serializers/api_keys.py +0 -51
  172. django_cfg/apps/payments/serializers/balance.py +0 -59
  173. django_cfg/apps/payments/serializers/currencies.py +0 -63
  174. django_cfg/apps/payments/serializers/payments.py +0 -62
  175. django_cfg/apps/payments/serializers/subscriptions.py +0 -71
  176. django_cfg/apps/payments/serializers/tariffs.py +0 -56
  177. django_cfg/apps/payments/services/billing/__init__.py +0 -8
  178. django_cfg/apps/payments/services/cache/base.py +0 -30
  179. django_cfg/apps/payments/services/core/fallback_service.py +0 -432
  180. django_cfg/apps/payments/services/internal_types.py +0 -461
  181. django_cfg/apps/payments/services/middleware/__init__.py +0 -8
  182. django_cfg/apps/payments/services/monitoring/__init__.py +0 -22
  183. django_cfg/apps/payments/services/monitoring/api_schemas.py +0 -76
  184. django_cfg/apps/payments/services/monitoring/provider_health.py +0 -372
  185. django_cfg/apps/payments/services/providers/cryptapi/__init__.py +0 -4
  186. django_cfg/apps/payments/services/providers/cryptapi/config.py +0 -8
  187. django_cfg/apps/payments/services/providers/cryptapi/models.py +0 -192
  188. django_cfg/apps/payments/services/providers/cryptapi/provider.py +0 -439
  189. django_cfg/apps/payments/services/providers/cryptomus/__init__.py +0 -4
  190. django_cfg/apps/payments/services/providers/cryptomus/models.py +0 -176
  191. django_cfg/apps/payments/services/providers/cryptomus/provider.py +0 -429
  192. django_cfg/apps/payments/services/providers/cryptomus/provider_v2.py +0 -564
  193. django_cfg/apps/payments/services/providers/models/__init__.py +0 -34
  194. django_cfg/apps/payments/services/providers/models/currencies.py +0 -190
  195. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +0 -4
  196. django_cfg/apps/payments/services/providers/nowpayments/models.py +0 -196
  197. django_cfg/apps/payments/services/providers/nowpayments/provider.py +0 -380
  198. django_cfg/apps/payments/services/providers/stripe/__init__.py +0 -4
  199. django_cfg/apps/payments/services/providers/stripe/models.py +0 -184
  200. django_cfg/apps/payments/services/providers/stripe/provider.py +0 -109
  201. django_cfg/apps/payments/services/security/__init__.py +0 -34
  202. django_cfg/apps/payments/services/security/error_handler.py +0 -635
  203. django_cfg/apps/payments/services/security/payment_notifications.py +0 -342
  204. django_cfg/apps/payments/services/security/webhook_validator.py +0 -474
  205. django_cfg/apps/payments/static/payments/css/payments.css +0 -340
  206. django_cfg/apps/payments/static/payments/js/notifications.js +0 -202
  207. django_cfg/apps/payments/static/payments/js/payment-utils.js +0 -318
  208. django_cfg/apps/payments/static/payments/js/theme.js +0 -86
  209. django_cfg/apps/payments/tasks/__init__.py +0 -12
  210. django_cfg/apps/payments/tasks/webhook_processing.py +0 -177
  211. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +0 -50
  212. django_cfg/apps/payments/templates/payments/base.html +0 -182
  213. django_cfg/apps/payments/templates/payments/components/payment_card.html +0 -201
  214. django_cfg/apps/payments/templates/payments/components/payment_qr_code.html +0 -109
  215. django_cfg/apps/payments/templates/payments/components/progress_bar.html +0 -43
  216. django_cfg/apps/payments/templates/payments/components/provider_stats.html +0 -40
  217. django_cfg/apps/payments/templates/payments/components/status_badge.html +0 -34
  218. django_cfg/apps/payments/templates/payments/components/status_overview.html +0 -148
  219. django_cfg/apps/payments/templates/payments/dashboard.html +0 -258
  220. django_cfg/apps/payments/templates/payments/dashboard_simple_test.html +0 -35
  221. django_cfg/apps/payments/templates/payments/payment_create.html +0 -579
  222. django_cfg/apps/payments/templates/payments/payment_detail.html +0 -373
  223. django_cfg/apps/payments/templates/payments/payment_list.html +0 -354
  224. django_cfg/apps/payments/templates/payments/stats.html +0 -261
  225. django_cfg/apps/payments/templates/payments/test.html +0 -213
  226. django_cfg/apps/payments/templatetags/payments_tags.py +0 -315
  227. django_cfg/apps/payments/utils/__init__.py +0 -43
  228. django_cfg/apps/payments/utils/billing_utils.py +0 -342
  229. django_cfg/apps/payments/utils/config_utils.py +0 -239
  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 -63
  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 -122
  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 -451
  241. django_cfg/apps/payments/views/templates/base.py +0 -212
  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 -158
  245. django_cfg/apps/payments/views/templates/qr_code.py +0 -174
  246. django_cfg/apps/payments/views/templates/stats.py +0 -244
  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 -66
  250. django_cfg/core/integration.py +0 -160
  251. django_cfg/template_archive/.gitignore +0 -1
  252. django_cfg/template_archive/__init__.py +0 -0
  253. django_cfg/urls.py +0 -33
  254. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/WHEEL +0 -0
  255. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/entry_points.txt +0 -0
  256. {django_cfg-1.2.31.dist-info → django_cfg-1.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,102 +1,209 @@
1
1
  """
2
- Tariff models for the universal payments system.
2
+ Tariff models for the Universal Payment System v2.0.
3
+
4
+ Handles pricing tiers and endpoint group associations.
3
5
  """
4
6
 
5
7
  from django.db import models
6
- from django.core.validators import MinValueValidator
8
+ from django.core.validators import MinValueValidator, MaxValueValidator
9
+ from django.core.exceptions import ValidationError
7
10
  from .base import TimestampedModel
11
+ from .subscriptions import EndpointGroup
8
12
 
9
13
 
10
14
  class Tariff(TimestampedModel):
11
- """Simple tariff plans for API access."""
15
+ """
16
+ Tariff model for subscription pricing tiers.
17
+
18
+ Defines pricing and limits for different subscription levels.
19
+ """
12
20
 
13
21
  name = models.CharField(
14
22
  max_length=100,
15
23
  unique=True,
16
- help_text="Tariff name"
24
+ help_text="Tariff name (e.g., 'Free', 'Basic', 'Pro')"
17
25
  )
18
- display_name = models.CharField(
19
- max_length=200,
20
- help_text="Human-readable tariff name"
26
+
27
+ code = models.CharField(
28
+ max_length=50,
29
+ unique=True,
30
+ help_text="Tariff code (e.g., 'free', 'basic', 'pro')"
21
31
  )
32
+
22
33
  description = models.TextField(
23
34
  blank=True,
24
- help_text="Tariff description"
35
+ help_text="Detailed description of what this tariff includes"
25
36
  )
26
37
 
27
38
  # Pricing
28
- monthly_price = models.FloatField(
29
- default=0.0,
39
+ monthly_price_usd = models.FloatField(
30
40
  validators=[MinValueValidator(0.0)],
31
41
  help_text="Monthly price in USD"
32
42
  )
33
43
 
34
- # Limits
35
- request_limit = models.PositiveIntegerField(
44
+ yearly_price_usd = models.FloatField(
45
+ null=True,
46
+ blank=True,
47
+ validators=[MinValueValidator(0.0)],
48
+ help_text="Yearly price in USD (optional discount)"
49
+ )
50
+
51
+ # Rate limits
52
+ requests_per_hour = models.PositiveIntegerField(
53
+ default=100,
54
+ validators=[MinValueValidator(1), MaxValueValidator(100000)],
55
+ help_text="API requests allowed per hour"
56
+ )
57
+
58
+ requests_per_day = models.PositiveIntegerField(
36
59
  default=1000,
37
- help_text="Monthly request limit (0 = unlimited)"
60
+ validators=[MinValueValidator(1), MaxValueValidator(1000000)],
61
+ help_text="API requests allowed per day"
62
+ )
63
+
64
+ requests_per_month = models.PositiveIntegerField(
65
+ default=30000,
66
+ validators=[MinValueValidator(1), MaxValueValidator(10000000)],
67
+ help_text="API requests allowed per month"
68
+ )
69
+
70
+ # Features
71
+ max_api_keys = models.PositiveIntegerField(
72
+ default=1,
73
+ validators=[MinValueValidator(1), MaxValueValidator(100)],
74
+ help_text="Maximum number of API keys allowed"
75
+ )
76
+
77
+ supports_webhooks = models.BooleanField(
78
+ default=True,
79
+ help_text="Whether webhooks are supported"
80
+ )
81
+
82
+ priority_support = models.BooleanField(
83
+ default=False,
84
+ help_text="Whether priority support is included"
38
85
  )
39
86
 
40
- # Settings
87
+ # Availability
41
88
  is_active = models.BooleanField(
42
89
  default=True,
43
- help_text="Is this tariff active"
90
+ help_text="Whether this tariff is available for new subscriptions"
44
91
  )
45
92
 
46
- # Import and assign manager
47
- from ..managers import TariffManager
48
- objects = TariffManager()
93
+ is_public = models.BooleanField(
94
+ default=True,
95
+ help_text="Whether this tariff is publicly visible"
96
+ )
97
+
98
+ # Ordering
99
+ sort_order = models.PositiveIntegerField(
100
+ default=0,
101
+ help_text="Sort order for display (lower numbers first)"
102
+ )
49
103
 
50
104
  class Meta:
51
- db_table = 'tariffs'
52
- verbose_name = "Tariff"
53
- verbose_name_plural = "Tariffs"
105
+ db_table = 'payments_tariffs'
106
+ verbose_name = 'Tariff'
107
+ verbose_name_plural = 'Tariffs'
108
+ ordering = ['sort_order', 'monthly_price_usd']
54
109
  indexes = [
55
- models.Index(fields=['is_active']),
56
- models.Index(fields=['monthly_price']),
110
+ models.Index(fields=['is_active', 'is_public']),
111
+ models.Index(fields=['sort_order']),
57
112
  ]
58
- ordering = ['monthly_price']
59
113
 
60
114
  def __str__(self):
61
- return f"{self.display_name} (${self.monthly_price}/month)"
115
+ return f"{self.name} - ${self.monthly_price_usd:.2f}/month"
116
+
117
+ def clean(self):
118
+ """Validate tariff data."""
119
+ if self.code:
120
+ self.code = self.code.lower().replace(' ', '_')
121
+
122
+ # Validate rate limits hierarchy
123
+ if self.requests_per_day < self.requests_per_hour:
124
+ raise ValidationError("Daily limit cannot be less than hourly limit")
125
+
126
+ if self.requests_per_month < self.requests_per_day:
127
+ raise ValidationError("Monthly limit cannot be less than daily limit")
128
+
129
+ # Validate yearly pricing
130
+ if self.yearly_price_usd and self.yearly_price_usd >= (self.monthly_price_usd * 12):
131
+ raise ValidationError("Yearly price should be less than 12x monthly price")
62
132
 
63
133
  @property
64
134
  def is_free(self) -> bool:
65
135
  """Check if this is a free tariff."""
66
- return self.monthly_price == 0
136
+ return self.monthly_price_usd == 0.0
137
+
138
+ @property
139
+ def yearly_discount_percentage(self) -> float:
140
+ """Calculate yearly discount percentage."""
141
+ if not self.yearly_price_usd or self.monthly_price_usd == 0:
142
+ return 0.0
143
+
144
+ yearly_equivalent = self.monthly_price_usd * 12
145
+ discount = yearly_equivalent - self.yearly_price_usd
146
+ return (discount / yearly_equivalent) * 100
147
+
148
+ @property
149
+ def price_display(self) -> str:
150
+ """Formatted price display."""
151
+ if self.is_free:
152
+ return "Free"
153
+ return f"${self.monthly_price_usd:.2f}/month"
154
+
155
+ @property
156
+ def yearly_price_display(self) -> str:
157
+ """Formatted yearly price display."""
158
+ if not self.yearly_price_usd:
159
+ return "N/A"
160
+ if self.yearly_price_usd == 0:
161
+ return "Free"
162
+ return f"${self.yearly_price_usd:.2f}/year"
67
163
 
68
164
 
69
165
  class TariffEndpointGroup(TimestampedModel):
70
- """Simple association between tariffs and endpoint groups."""
166
+ """
167
+ Association between tariffs and endpoint groups.
168
+
169
+ Defines which API endpoints are available for each tariff.
170
+ """
71
171
 
72
172
  tariff = models.ForeignKey(
73
173
  Tariff,
74
174
  on_delete=models.CASCADE,
75
- related_name='endpoint_groups',
76
- help_text="Tariff plan"
175
+ related_name='endpoint_groups'
77
176
  )
78
- from .subscriptions import EndpointGroup
177
+
79
178
  endpoint_group = models.ForeignKey(
80
179
  EndpointGroup,
81
180
  on_delete=models.CASCADE,
82
- related_name='tariffs',
83
- help_text="Endpoint group"
181
+ related_name='tariffs'
182
+ )
183
+
184
+ # Override default rate limits for this specific combination
185
+ custom_rate_limit = models.PositiveIntegerField(
186
+ null=True,
187
+ blank=True,
188
+ help_text="Custom rate limit for this endpoint group (overrides tariff default)"
84
189
  )
85
190
 
86
191
  is_enabled = models.BooleanField(
87
192
  default=True,
88
- help_text="Is this endpoint group enabled for this tariff"
193
+ help_text="Whether this endpoint group is enabled for this tariff"
89
194
  )
90
195
 
91
- # Import and assign manager
92
- from ..managers import TariffEndpointGroupManager
93
- objects = TariffEndpointGroupManager()
94
-
95
196
  class Meta:
96
- db_table = 'tariff_endpoint_groups'
97
- verbose_name = "Tariff Endpoint Group"
98
- verbose_name_plural = "Tariff Endpoint Groups"
197
+ db_table = 'payments_tariff_endpoint_groups'
198
+ verbose_name = 'Tariff Endpoint Group'
199
+ verbose_name_plural = 'Tariff Endpoint Groups'
99
200
  unique_together = [['tariff', 'endpoint_group']]
201
+ ordering = ['tariff__sort_order', 'endpoint_group__name']
100
202
 
101
203
  def __str__(self):
102
204
  return f"{self.tariff.name} - {self.endpoint_group.name}"
205
+
206
+ @property
207
+ def effective_rate_limit(self) -> int:
208
+ """Get effective rate limit (custom or tariff default)."""
209
+ return self.custom_rate_limit or self.tariff.requests_per_hour
@@ -1,71 +1,224 @@
1
1
  """
2
- Universal Payment Services.
2
+ Services package for the Universal Payment System v2.0.
3
3
 
4
- Modular architecture with minimal Pydantic typing for inter-service communication.
5
- Uses Django ORM for data persistence and DRF for API responses.
4
+ Business logic services with Pydantic validation and type safety.
6
5
  """
7
6
 
8
7
  # Core services
9
- from .core.payment_service import PaymentService
10
- from .core.balance_service import BalanceService
11
- from .core.subscription_service import SubscriptionService
12
-
13
- # Provider services
14
- from .providers.registry import ProviderRegistry
15
- from .providers.nowpayments import NowPaymentsProvider
16
- from .providers.cryptapi import CryptAPIProvider
17
-
18
- # Cache services
19
- from .cache import SimpleCache, ApiKeyCache, RateLimitCache
20
-
21
- # Internal types for inter-service communication
22
- from .internal_types import (
23
- ProviderResponse, WebhookData, ServiceOperationResult,
24
- BalanceUpdateRequest, AccessCheckRequest, AccessCheckResult,
25
- # Service response models
26
- PaymentCreationResult, WebhookProcessingResult, PaymentStatusResult,
27
- UserBalanceResult, TransferResult, TransactionInfo,
28
- EndpointGroupInfo, SubscriptionInfo, SubscriptionAnalytics,
29
- # Additional response models
30
- PaymentHistoryItem, ProviderInfo
8
+ from .core import (
9
+ BaseService,
10
+ PaymentService,
11
+ BalanceService,
12
+ SubscriptionService,
13
+ WebhookService,
14
+ CurrencyService,
15
+ )
16
+
17
+ # Service types
18
+ from .types import (
19
+ # Request types
20
+ PaymentCreateRequest,
21
+ PaymentStatusRequest,
22
+ BalanceUpdateRequest,
23
+ SubscriptionCreateRequest,
24
+ SubscriptionUpdateRequest,
25
+ CurrencyConversionRequest,
26
+
27
+ # Response types
28
+ PaymentResult,
29
+ BalanceResult,
30
+ SubscriptionResult,
31
+ CurrencyConversionResult,
32
+ ServiceOperationResult,
33
+
34
+ # Data types
35
+ PaymentData,
36
+ BalanceData,
37
+ SubscriptionData,
38
+ TransactionData,
39
+ CurrencyData,
40
+
41
+ # Webhook types
42
+ WebhookData,
43
+ NowPaymentsWebhook,
44
+ WebhookProcessingResult,
31
45
  )
32
46
 
33
47
  __all__ = [
34
48
  # Core services
49
+ 'BaseService',
35
50
  'PaymentService',
36
- 'BalanceService',
51
+ 'BalanceService',
37
52
  'SubscriptionService',
53
+ 'WebhookService',
54
+ 'CurrencyService',
38
55
 
39
- # Provider services
40
- 'ProviderRegistry',
41
- 'NowPaymentsProvider',
42
- 'CryptAPIProvider',
43
-
44
- # Cache services
45
- 'SimpleCache',
46
- 'ApiKeyCache',
47
- 'RateLimitCache',
56
+ # Request types
57
+ 'PaymentCreateRequest',
58
+ 'PaymentStatusRequest',
59
+ 'BalanceUpdateRequest',
60
+ 'SubscriptionCreateRequest',
61
+ 'SubscriptionUpdateRequest',
62
+ 'CurrencyConversionRequest',
48
63
 
49
- # Internal types
50
- 'ProviderResponse',
51
- 'WebhookData',
64
+ # Response types
65
+ 'PaymentResult',
66
+ 'BalanceResult',
67
+ 'SubscriptionResult',
68
+ 'CurrencyConversionResult',
52
69
  'ServiceOperationResult',
53
- 'BalanceUpdateRequest',
54
- 'AccessCheckRequest',
55
- 'AccessCheckResult',
56
-
57
- # Service response models
58
- 'PaymentCreationResult',
59
- 'WebhookProcessingResult',
60
- 'PaymentStatusResult',
61
- 'UserBalanceResult',
62
- 'TransferResult',
63
- 'TransactionInfo',
64
- 'EndpointGroupInfo',
65
- 'SubscriptionInfo',
66
- 'SubscriptionAnalytics',
67
-
68
- # Additional response models
69
- 'PaymentHistoryItem',
70
- 'ProviderInfo',
70
+
71
+ # Data types
72
+ 'PaymentData',
73
+ 'BalanceData',
74
+ 'SubscriptionData',
75
+ 'TransactionData',
76
+ 'CurrencyData',
77
+
78
+ # Webhook types
79
+ 'WebhookData',
80
+ 'NowPaymentsWebhook',
81
+ 'WebhookProcessingResult',
71
82
  ]
83
+
84
+
85
+ # Service registry for dependency injection and health checks
86
+ class ServiceRegistry:
87
+ """
88
+ Service registry for managing service instances.
89
+
90
+ Provides singleton access to services and health monitoring.
91
+ """
92
+
93
+ _instances = {}
94
+
95
+ @classmethod
96
+ def get_payment_service(cls) -> PaymentService:
97
+ """Get PaymentService instance."""
98
+ if 'payment' not in cls._instances:
99
+ cls._instances['payment'] = PaymentService()
100
+ return cls._instances['payment']
101
+
102
+ @classmethod
103
+ def get_balance_service(cls) -> BalanceService:
104
+ """Get BalanceService instance."""
105
+ if 'balance' not in cls._instances:
106
+ cls._instances['balance'] = BalanceService()
107
+ return cls._instances['balance']
108
+
109
+ @classmethod
110
+ def get_subscription_service(cls) -> SubscriptionService:
111
+ """Get SubscriptionService instance."""
112
+ if 'subscription' not in cls._instances:
113
+ cls._instances['subscription'] = SubscriptionService()
114
+ return cls._instances['subscription']
115
+
116
+ @classmethod
117
+ def get_webhook_service(cls) -> WebhookService:
118
+ """Get WebhookService instance."""
119
+ if 'webhook' not in cls._instances:
120
+ cls._instances['webhook'] = WebhookService()
121
+ return cls._instances['webhook']
122
+
123
+ @classmethod
124
+ def get_currency_service(cls) -> CurrencyService:
125
+ """Get CurrencyService instance."""
126
+ if 'currency' not in cls._instances:
127
+ cls._instances['currency'] = CurrencyService()
128
+ return cls._instances['currency']
129
+
130
+ @classmethod
131
+ def get_all_services(cls) -> dict:
132
+ """Get all service instances."""
133
+ return {
134
+ 'payment': cls.get_payment_service(),
135
+ 'balance': cls.get_balance_service(),
136
+ 'subscription': cls.get_subscription_service(),
137
+ 'webhook': cls.get_webhook_service(),
138
+ 'currency': cls.get_currency_service(),
139
+ }
140
+
141
+ @classmethod
142
+ def health_check_all(cls) -> dict:
143
+ """Perform health check on all services."""
144
+ services = cls.get_all_services()
145
+ results = {}
146
+
147
+ for name, service in services.items():
148
+ try:
149
+ health_result = service.health_check()
150
+ results[name] = {
151
+ 'healthy': health_result.success,
152
+ 'message': health_result.message,
153
+ 'data': health_result.data
154
+ }
155
+ except Exception as e:
156
+ results[name] = {
157
+ 'healthy': False,
158
+ 'message': f"Health check failed: {e}",
159
+ 'data': {}
160
+ }
161
+
162
+ return results
163
+
164
+ @classmethod
165
+ def clear_cache_all(cls):
166
+ """Clear cache for all services."""
167
+ for service in cls._instances.values():
168
+ if hasattr(service, '_cache_clear'):
169
+ service._cache_clear()
170
+
171
+ @classmethod
172
+ def get_stats_all(cls) -> dict:
173
+ """Get statistics from all services."""
174
+ services = cls.get_all_services()
175
+ stats = {}
176
+
177
+ for name, service in services.items():
178
+ try:
179
+ service_stats = service.get_service_stats()
180
+ stats[name] = service_stats
181
+ except Exception as e:
182
+ stats[name] = {
183
+ 'error': str(e),
184
+ 'service_name': service.__class__.__name__
185
+ }
186
+
187
+ return stats
188
+
189
+
190
+ # Convenience functions for direct service access
191
+ def get_payment_service() -> PaymentService:
192
+ """Get PaymentService instance."""
193
+ return ServiceRegistry.get_payment_service()
194
+
195
+
196
+ def get_balance_service() -> BalanceService:
197
+ """Get BalanceService instance."""
198
+ return ServiceRegistry.get_balance_service()
199
+
200
+
201
+ def get_subscription_service() -> SubscriptionService:
202
+ """Get SubscriptionService instance."""
203
+ return ServiceRegistry.get_subscription_service()
204
+
205
+
206
+ def get_webhook_service() -> WebhookService:
207
+ """Get WebhookService instance."""
208
+ return ServiceRegistry.get_webhook_service()
209
+
210
+
211
+ def get_currency_service() -> CurrencyService:
212
+ """Get CurrencyService instance."""
213
+ return ServiceRegistry.get_currency_service()
214
+
215
+
216
+ # Add convenience functions to __all__
217
+ __all__.extend([
218
+ 'ServiceRegistry',
219
+ 'get_payment_service',
220
+ 'get_balance_service',
221
+ 'get_subscription_service',
222
+ 'get_webhook_service',
223
+ 'get_currency_service',
224
+ ])
@@ -1,15 +1,15 @@
1
1
  """
2
- Simple caching for API key access control and rate limiting.
2
+ Cache services for the Universal Payment System v2.0.
3
3
 
4
- ONLY for API key caching - NOT for payment data!
4
+ Redis-backed caching with type safety and automatic key management.
5
5
  """
6
6
 
7
- from .base import CacheInterface
8
- from .simple_cache import SimpleCache, ApiKeyCache, RateLimitCache
7
+ from .cache_service import CacheService, get_cache_service, SimpleCache, ApiKeyCache, RateLimitCache
9
8
 
10
9
  __all__ = [
11
- 'CacheInterface',
12
- 'SimpleCache',
10
+ 'CacheService',
11
+ 'get_cache_service',
13
12
  'ApiKeyCache',
14
13
  'RateLimitCache',
14
+ 'SimpleCache',
15
15
  ]