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,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
  ]