ipulse-shared-core-ftredge 20.0.1__py3-none-any.whl → 23.1.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.

Potentially problematic release.


This version of ipulse-shared-core-ftredge might be problematic. Click here for more details.

Files changed (48) hide show
  1. ipulse_shared_core_ftredge/cache/shared_cache.py +1 -2
  2. ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py +60 -23
  3. ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +128 -157
  4. ipulse_shared_core_ftredge/exceptions/base_exceptions.py +35 -4
  5. ipulse_shared_core_ftredge/models/__init__.py +3 -7
  6. ipulse_shared_core_ftredge/models/base_data_model.py +17 -19
  7. ipulse_shared_core_ftredge/models/catalog/__init__.py +10 -0
  8. ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py +274 -0
  9. ipulse_shared_core_ftredge/models/catalog/usertype.py +177 -0
  10. ipulse_shared_core_ftredge/models/user/__init__.py +5 -0
  11. ipulse_shared_core_ftredge/models/user/user_permissions.py +66 -0
  12. ipulse_shared_core_ftredge/models/user/user_subscription.py +348 -0
  13. ipulse_shared_core_ftredge/models/{user_auth.py → user/userauth.py} +19 -10
  14. ipulse_shared_core_ftredge/models/{user_profile.py → user/userprofile.py} +53 -21
  15. ipulse_shared_core_ftredge/models/user/userstatus.py +479 -0
  16. ipulse_shared_core_ftredge/monitoring/__init__.py +0 -2
  17. ipulse_shared_core_ftredge/monitoring/tracemon.py +6 -6
  18. ipulse_shared_core_ftredge/services/__init__.py +11 -13
  19. ipulse_shared_core_ftredge/services/base/__init__.py +3 -1
  20. ipulse_shared_core_ftredge/services/base/base_firestore_service.py +77 -16
  21. ipulse_shared_core_ftredge/services/{cache_aware_firestore_service.py → base/cache_aware_firestore_service.py} +46 -32
  22. ipulse_shared_core_ftredge/services/catalog/__init__.py +14 -0
  23. ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py +277 -0
  24. ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +376 -0
  25. ipulse_shared_core_ftredge/services/charging_processors.py +25 -25
  26. ipulse_shared_core_ftredge/services/user/__init__.py +5 -25
  27. ipulse_shared_core_ftredge/services/user/user_core_service.py +536 -510
  28. ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +796 -0
  29. ipulse_shared_core_ftredge/services/user/user_permissions_operations.py +392 -0
  30. ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +488 -0
  31. ipulse_shared_core_ftredge/services/user/userauth_operations.py +928 -0
  32. ipulse_shared_core_ftredge/services/user/userprofile_operations.py +166 -0
  33. ipulse_shared_core_ftredge/services/user/userstatus_operations.py +476 -0
  34. ipulse_shared_core_ftredge/services/{charging_service.py → user_charging_service.py} +9 -9
  35. {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/METADATA +3 -4
  36. ipulse_shared_core_ftredge-23.1.1.dist-info/RECORD +50 -0
  37. ipulse_shared_core_ftredge/models/subscription.py +0 -190
  38. ipulse_shared_core_ftredge/models/user_status.py +0 -495
  39. ipulse_shared_core_ftredge/monitoring/microservmon.py +0 -526
  40. ipulse_shared_core_ftredge/services/user/iam_management_operations.py +0 -326
  41. ipulse_shared_core_ftredge/services/user/subscription_management_operations.py +0 -384
  42. ipulse_shared_core_ftredge/services/user/user_account_operations.py +0 -479
  43. ipulse_shared_core_ftredge/services/user/user_auth_operations.py +0 -305
  44. ipulse_shared_core_ftredge/services/user/user_holistic_operations.py +0 -436
  45. ipulse_shared_core_ftredge-20.0.1.dist-info/RECORD +0 -42
  46. {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/WHEEL +0 -0
  47. {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/licenses/LICENCE +0 -0
  48. {ipulse_shared_core_ftredge-20.0.1.dist-info → ipulse_shared_core_ftredge-23.1.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,376 @@
1
+ """
2
+ usertype Catalog Service
3
+
4
+ This service manages usertype templates stored in Firestore.
5
+ These templates are used to configure default settings for user profiles and statuses.
6
+ """
7
+
8
+ import logging
9
+ from typing import Dict, List, Optional, Any
10
+ from google.cloud.firestore import Client , Query
11
+ from ipulse_shared_base_ftredge import IAMUserType
12
+ from ipulse_shared_base_ftredge.enums.enums_status import ObjectOverallStatus
13
+ from ipulse_shared_core_ftredge.models.catalog.usertype import UserType
14
+ from ipulse_shared_core_ftredge.services.base.base_firestore_service import BaseFirestoreService
15
+
16
+ class CatalogUserTypeService(BaseFirestoreService[UserType]):
17
+ """
18
+ Service for managing usertype catalog configurations.
19
+
20
+ This service provides CRUD operations for usertype templates that define
21
+ the default settings and permissions for different usertypes.
22
+ """
23
+
24
+ def __init__(
25
+ self,
26
+ firestore_client: Client,
27
+ logger: Optional[logging.Logger] = None
28
+ ):
29
+ """
30
+ Initialize the usertype Catalog Service.
31
+
32
+ Args:
33
+ firestore_client: Firestore client instance
34
+ logger: Logger instance (optional)
35
+ """
36
+ super().__init__(
37
+ db=firestore_client,
38
+ collection_name="papp_core_catalog_usertypes",
39
+ resource_type="usertype",
40
+ model_class=UserType,
41
+ logger=logger or logging.getLogger(__name__)
42
+ )
43
+ self.archive_collection_name = "~archive_papp_core_catalog_usertypes"
44
+
45
+ async def create_usertype(
46
+ self,
47
+ usertype_id: str,
48
+ user_type: UserType,
49
+ creator_uid: str
50
+ ) -> UserType:
51
+ """
52
+ Create a new usertype.
53
+
54
+ Args:
55
+ usertype_id: Unique identifier for the usertype
56
+ user_type: Usertype data
57
+ creator_uid: UID of the user creating the usertype
58
+
59
+ Returns:
60
+ Created usertype
61
+
62
+ Raises:
63
+ ServiceError: If creation fails
64
+ ValidationError: If usertype data is invalid
65
+ """
66
+ self.logger.info(f"Creating usertype: {usertype_id}")
67
+
68
+ # Create the document
69
+ created_doc = await self.create_document(
70
+ doc_id=usertype_id,
71
+ data=user_type,
72
+ creator_uid=creator_uid
73
+ )
74
+
75
+ # Convert back to model
76
+ result = UserType.model_validate(created_doc)
77
+ self.logger.info(f"Successfully created usertype: {usertype_id}")
78
+ return result
79
+
80
+ async def get_usertype(self, usertype_id: str) -> Optional[UserType]:
81
+ """
82
+ Retrieve a usertype by ID.
83
+
84
+ Args:
85
+ usertype_id: Unique identifier for the usertype
86
+
87
+ Returns:
88
+ usertype if found, None otherwise
89
+
90
+ Raises:
91
+ ServiceError: If retrieval fails
92
+ """
93
+ self.logger.debug(f"Retrieving usertype: {usertype_id}")
94
+ doc_data = await self.get_document(usertype_id)
95
+ if doc_data is None:
96
+ return None
97
+ return UserType.model_validate(doc_data) if isinstance(doc_data, dict) else doc_data
98
+
99
+ async def update_usertype(
100
+ self,
101
+ usertype_id: str,
102
+ updates: Dict[str, Any],
103
+ updater_uid: str
104
+ ) -> UserType:
105
+ """
106
+ Update a usertype.
107
+
108
+ Args:
109
+ usertype_id: Unique identifier for the usertype
110
+ updates: Fields to update
111
+ updater_uid: UID of the user updating the usertype
112
+
113
+ Returns:
114
+ Updated usertype
115
+
116
+ Raises:
117
+ ServiceError: If update fails
118
+ ResourceNotFoundError: If usertype not found
119
+ ValidationError: If update data is invalid
120
+ """
121
+ self.logger.info(f"Updating usertype: {usertype_id}")
122
+
123
+ updated_doc = await self.update_document(
124
+ doc_id=usertype_id,
125
+ update_data=updates,
126
+ updater_uid=updater_uid
127
+ )
128
+
129
+ result = UserType.model_validate(updated_doc)
130
+ self.logger.info(f"Successfully updated usertype: {usertype_id}")
131
+ return result
132
+
133
+ async def delete_usertype(
134
+ self,
135
+ usertype_id: str,
136
+ archive: bool = True
137
+ ) -> bool:
138
+ """
139
+ Delete a usertype.
140
+
141
+ Args:
142
+ usertype_id: Unique identifier for the usertype
143
+ archive: Whether to archive the usertype before deletion
144
+
145
+ Returns:
146
+ True if deletion was successful
147
+
148
+ Raises:
149
+ ServiceError: If deletion fails
150
+ ResourceNotFoundError: If usertype not found
151
+ """
152
+ self.logger.info(f"Deleting usertype: {usertype_id}")
153
+
154
+ if archive:
155
+ # Get the usertype data before deletion for archiving
156
+ template = await self.get_usertype(usertype_id)
157
+ if template:
158
+ await self.archive_document(
159
+ document_data=template.model_dump(),
160
+ doc_id=usertype_id,
161
+ archive_collection=self.archive_collection_name,
162
+ archived_by="system"
163
+ )
164
+
165
+ result = await self.delete_document(usertype_id)
166
+ self.logger.info(f"Successfully deleted usertype: {usertype_id}")
167
+ return result
168
+
169
+ async def list_usertypes(
170
+ self,
171
+ primary_usertype: Optional[IAMUserType] = None,
172
+ pulse_status: Optional[ObjectOverallStatus] = None,
173
+ latest_version_only: bool = False,
174
+ limit: Optional[int] = None,
175
+ version_ordering: str = "DESCENDING"
176
+ ) -> List[UserType]:
177
+ """
178
+ List usertypes with optional filtering.
179
+
180
+ Args:
181
+ primary_usertype: Filter by specific primary usertype
182
+ pulse_status: Filter by specific pulse status
183
+ latest_version_only: Only return the latest version per usertype
184
+ limit: Maximum number of usertypes to return
185
+ version_ordering: Order direction for version ('ASCENDING' or 'DESCENDING')
186
+
187
+ Returns:
188
+ List of usertypes
189
+
190
+ Raises:
191
+ ServiceError: If listing fails
192
+ """
193
+ self.logger.debug(f"Listing usertypes - primary_usertype: {primary_usertype}, pulse_status: {pulse_status}, latest_version_only: {latest_version_only}, version_ordering: {version_ordering}")
194
+
195
+ # Build query filters
196
+ filters = []
197
+ if primary_usertype:
198
+ filters.append(("primary_usertype", "==", primary_usertype.value))
199
+ if pulse_status:
200
+ filters.append(("pulse_status", "==", pulse_status.value))
201
+
202
+ # Set ordering
203
+ order_by = "version"
204
+ order_direction = Query.DESCENDING if version_ordering == "DESCENDING" else Query.ASCENDING
205
+
206
+ # Optimize query if only the latest version of a specific usertype is needed
207
+ query_limit = limit
208
+ if latest_version_only and primary_usertype:
209
+ query_limit = 1
210
+ # Ensure descending order to get the latest
211
+ order_direction = Query.DESCENDING
212
+
213
+ docs = await self.list_documents(
214
+ filters=filters,
215
+ order_by=order_by,
216
+ order_direction=order_direction,
217
+ limit=query_limit
218
+ )
219
+
220
+ # Convert to UserType models
221
+ usertypes = [UserType.model_validate(doc) for doc in docs]
222
+
223
+ # If we need the latest of all usertypes, we fetch all sorted by version
224
+ # and then pick the first one for each primary_usertype in Python.
225
+ if latest_version_only and not primary_usertype:
226
+ # This assumes the list is sorted by version descending.
227
+ if order_direction != Query.DESCENDING:
228
+ self.logger.warning("latest_version_only is True but version_ordering is not DESCENDING. Results may not be the latest.")
229
+
230
+ usertype_groups = {}
231
+ for usertype in usertypes:
232
+ key = usertype.primary_usertype.value
233
+ if key not in usertype_groups:
234
+ usertype_groups[key] = usertype # First one is the latest due to sorting
235
+
236
+ return list(usertype_groups.values())
237
+
238
+ return usertypes
239
+
240
+ def _get_collection(self):
241
+ """Get the Firestore collection reference."""
242
+ return self.db.collection(self.collection_name)
243
+
244
+ async def usertype_exists(self, usertype_id: str) -> bool:
245
+ """
246
+ Check if a usertype exists.
247
+
248
+ Args:
249
+ usertype_id: Unique identifier for the usertype
250
+
251
+ Returns:
252
+ True if usertype exists, False otherwise
253
+
254
+ Raises:
255
+ ServiceError: If check fails
256
+ """
257
+ return await self.document_exists(usertype_id)
258
+
259
+ async def validate_usertype_data(self, usertype_data: Dict[str, Any]) -> tuple[bool, List[str]]:
260
+ """
261
+ Validate usertype data.
262
+
263
+ Args:
264
+ usertype_data: Usertype data to validate
265
+
266
+ Returns:
267
+ Tuple of (is_valid, list_of_errors)
268
+ """
269
+ try:
270
+ UserType.model_validate(usertype_data)
271
+ return True, []
272
+ except Exception as e:
273
+ return False, [str(e)]
274
+
275
+
276
+ async def get_default_credits_for_usertype(self, primary_usertype: IAMUserType) -> Dict[str, int]:
277
+ """
278
+ Get default credit settings for a specific usertype.
279
+
280
+ Args:
281
+ primary_usertype: The primary usertype
282
+
283
+ Returns:
284
+ Dictionary with default credit values
285
+
286
+ Raises:
287
+ ServiceError: If retrieval fails
288
+ """
289
+ self.logger.debug(f"Getting default credits for usertype: {primary_usertype}")
290
+
291
+ usertypes = await self.list_usertypes(
292
+ primary_usertype=primary_usertype,
293
+ pulse_status=ObjectOverallStatus.ACTIVE,
294
+ latest_version_only=True,
295
+ limit=1
296
+ )
297
+ usertype = usertypes[0] if usertypes else None
298
+ if not usertype:
299
+ self.logger.warning(f"No active usertype found for: {primary_usertype}")
300
+ return {
301
+ "subscription_based_insight_credits": 0,
302
+ "extra_insight_credits": 0,
303
+ "voting_credits": 0
304
+ }
305
+
306
+ return {
307
+ "extra_insight_credits": usertype.default_extra_insight_credits,
308
+ "voting_credits": usertype.default_voting_credits
309
+ }
310
+
311
+ async def fetch_catalog_usertype_based_on_email(
312
+ self,
313
+ email: str,
314
+ superadmins: Optional[List[str]] = None,
315
+ admins: Optional[List[str]] = None,
316
+ internal_domains: Optional[List[str]] = None
317
+ ) -> UserType:
318
+ """
319
+ Fetch the actual usertype from catalog based on email domain classification.
320
+
321
+ Args:
322
+ email: User's email address
323
+ superadmins: List of superadmin emails
324
+ admins: List of admin emails
325
+ internal_domains: List of internal domains
326
+
327
+ Returns:
328
+ UserType object from the catalog
329
+
330
+ Raises:
331
+ ServiceError: If no active usertype found for the determined primary_usertype
332
+ """
333
+ if not email:
334
+ primary_usertype = IAMUserType.CUSTOMER
335
+ else:
336
+ superadmins = superadmins or []
337
+ admins = admins or []
338
+ internal_domains = internal_domains or []
339
+
340
+ email_lower = email.lower()
341
+
342
+ if email_lower in [admin.lower() for admin in superadmins]:
343
+ primary_usertype = IAMUserType.SUPERADMIN
344
+ elif email_lower in [admin.lower() for admin in admins]:
345
+ primary_usertype = IAMUserType.ADMIN
346
+ else:
347
+ domain = email_lower.split('@')[-1] if '@' in email_lower else ''
348
+ if domain in internal_domains:
349
+ primary_usertype = IAMUserType.INTERNAL
350
+ else:
351
+ primary_usertype = IAMUserType.CUSTOMER
352
+
353
+ # Get the actual usertype from the catalog
354
+ usertypes = await self.list_usertypes(
355
+ primary_usertype=primary_usertype,
356
+ pulse_status=ObjectOverallStatus.ACTIVE,
357
+ latest_version_only=True,
358
+ limit=1
359
+ )
360
+
361
+ if not usertypes:
362
+ from ipulse_shared_core_ftredge.exceptions import ServiceError
363
+ raise ServiceError(
364
+ error=f"No active usertype found in catalog for primary_usertype '{primary_usertype.value}'",
365
+ resource_type="usertype",
366
+ operation="fetch_catalog_usertype_based_on_email",
367
+ additional_info={
368
+ "email": email,
369
+ "primary_usertype": primary_usertype.value,
370
+ "domain": email.split('@')[-1] if '@' in email else ''
371
+ }
372
+ )
373
+
374
+ usertype = usertypes[0]
375
+ self.logger.info(f"Found usertype '{usertype.id}' for email '{email}' with primary_usertype '{primary_usertype.value}'")
376
+ return usertype
@@ -1,7 +1,7 @@
1
1
  """Reusable credit checking and charging utilities for services."""
2
2
  import os
3
3
  from typing import Dict, Any, List, Optional, Callable, Awaitable, TypeVar
4
- from ipulse_shared_core_ftredge.services.charging_service import ChargingService, ValidationError
4
+ from ipulse_shared_core_ftredge.services.user_charging_service import UserChargingService, ValidationError
5
5
  import logging
6
6
 
7
7
  T = TypeVar('T')
@@ -9,8 +9,8 @@ T = TypeVar('T')
9
9
  class ChargingProcessor:
10
10
  """Handles credit checking and charging for both single item and batch access."""
11
11
 
12
- def __init__(self, charging_service: ChargingService, logger: logging.Logger):
13
- self.charging_service = charging_service
12
+ def __init__(self, user_charging_service: UserChargingService, logger: logging.Logger):
13
+ self.user_charging_service = user_charging_service
14
14
  self.logger = logger
15
15
 
16
16
  async def process_single_item_charging(
@@ -54,9 +54,9 @@ class ChargingProcessor:
54
54
  # For free items, provide current credits if available
55
55
  if pre_fetched_credits:
56
56
  updated_user_credits = pre_fetched_credits
57
- elif self.charging_service: # Attempt to get current credits if not pre-fetched
57
+ elif self.user_charging_service: # Attempt to get current credits if not pre-fetched
58
58
  try:
59
- _, current_user_credits_from_verify = await self.charging_service.verify_credits(user_uid, 0, None)
59
+ _, current_user_credits_from_verify = await self.user_charging_service.verify_credits(user_uid, 0, None)
60
60
  updated_user_credits = current_user_credits_from_verify
61
61
  except Exception: # pylint: disable=broad-except
62
62
  self.logger.warning(f"Could not fetch current credits for user {user_uid} for free item.")
@@ -75,9 +75,9 @@ class ChargingProcessor:
75
75
  # Similar to free items, provide current credits if available
76
76
  if pre_fetched_credits:
77
77
  updated_user_credits = pre_fetched_credits
78
- elif self.charging_service:
78
+ elif self.user_charging_service:
79
79
  try:
80
- _, current_user_credits_from_verify = await self.charging_service.verify_credits(user_uid, 0, None)
80
+ _, current_user_credits_from_verify = await self.user_charging_service.verify_credits(user_uid, 0, None)
81
81
  updated_user_credits = current_user_credits_from_verify
82
82
  except Exception: # pylint: disable=broad-except
83
83
  self.logger.warning(f"Could not fetch current credits for user {user_uid} during debug bypass.")
@@ -90,7 +90,7 @@ class ChargingProcessor:
90
90
  }
91
91
 
92
92
  # Verify credit service is available
93
- if not self.charging_service:
93
+ if not self.user_charging_service:
94
94
  self.logger.error("ChargingService not initialized.")
95
95
  return {
96
96
  'access_granted': False,
@@ -101,7 +101,7 @@ class ChargingProcessor:
101
101
  }
102
102
 
103
103
  # Verify user has enough credits
104
- has_credits, current_user_credits_from_verify = await self.charging_service.verify_credits(
104
+ has_credits, current_user_credits_from_verify = await self.user_charging_service.verify_credits(
105
105
  user_uid,
106
106
  credit_cost,
107
107
  pre_fetched_user_credits=pre_fetched_credits
@@ -121,7 +121,7 @@ class ChargingProcessor:
121
121
  }
122
122
 
123
123
  # Charge the user - this now returns (bool, Optional[Dict])
124
- charged, calculated_updated_credits = await self.charging_service.charge_credits_transaction(
124
+ charged, calculated_updated_credits = await self.user_charging_service.charge_credits_transaction(
125
125
  user_uid,
126
126
  credit_cost,
127
127
  operation_description
@@ -143,9 +143,9 @@ class ChargingProcessor:
143
143
  except ValidationError as ve:
144
144
  self.logger.error(f"Validation error for item {item_id}, user {user_uid}: {str(ve)}")
145
145
  # Try to get current credits to return
146
- if self.charging_service:
146
+ if self.user_charging_service:
147
147
  try:
148
- _, updated_user_credits = await self.charging_service.verify_credits(user_uid, 0, pre_fetched_credits)
148
+ _, updated_user_credits = await self.user_charging_service.verify_credits(user_uid, 0, pre_fetched_credits)
149
149
  except Exception: # pylint: disable=broad-except
150
150
  pass # Keep updated_user_credits as None
151
151
  ve.additional_info = ve.additional_info or {}
@@ -155,9 +155,9 @@ class ChargingProcessor:
155
155
  self.logger.error(f"Unexpected error during credit processing for item {item_id}, user {user_uid}: {str(e)}", exc_info=True)
156
156
  # Try to get current credits to return
157
157
  current_user_credits_on_error = None
158
- if self.charging_service:
158
+ if self.user_charging_service:
159
159
  try:
160
- _, current_user_credits_on_error = await self.charging_service.verify_credits(user_uid, 0, pre_fetched_credits)
160
+ _, current_user_credits_on_error = await self.user_charging_service.verify_credits(user_uid, 0, pre_fetched_credits)
161
161
  except Exception: # pylint: disable=broad-except
162
162
  pass
163
163
  return {
@@ -228,9 +228,9 @@ class ChargingProcessor:
228
228
  if not paid_items:
229
229
  if pre_fetched_credits:
230
230
  updated_user_credits = pre_fetched_credits
231
- elif self.charging_service:
231
+ elif self.user_charging_service:
232
232
  try:
233
- _, current_user_credits_from_verify = await self.charging_service.verify_credits(user_uid, 0, None)
233
+ _, current_user_credits_from_verify = await self.user_charging_service.verify_credits(user_uid, 0, None)
234
234
  updated_user_credits = current_user_credits_from_verify
235
235
 
236
236
  except Exception: # pylint: disable=broad-except
@@ -250,9 +250,9 @@ class ChargingProcessor:
250
250
  self.logger.info(f"Bypassing credit check for {len(paid_items)} paid items due to debug mode")
251
251
  if pre_fetched_credits:
252
252
  updated_user_credits = pre_fetched_credits
253
- elif self.charging_service:
253
+ elif self.user_charging_service:
254
254
  try:
255
- _, current_user_credits_from_verify = await self.charging_service.verify_credits(user_uid, 0, None)
255
+ _, current_user_credits_from_verify = await self.user_charging_service.verify_credits(user_uid, 0, None)
256
256
  updated_user_credits = current_user_credits_from_verify
257
257
  except Exception: # pylint: disable=broad-except
258
258
  self.logger.warning(f"Could not fetch current credits for user {user_uid} during debug bypass for batch.")
@@ -267,7 +267,7 @@ class ChargingProcessor:
267
267
  }
268
268
 
269
269
  # Verify credit service is available
270
- if not self.charging_service:
270
+ if not self.user_charging_service:
271
271
  self.logger.error("ChargingService not initialized for batch processing.")
272
272
  return {
273
273
  'accessible_items': free_items,
@@ -280,7 +280,7 @@ class ChargingProcessor:
280
280
 
281
281
  try:
282
282
  # Verify user has enough credits for total cost
283
- has_credits, current_user_credits_from_verify = await self.charging_service.verify_credits(
283
+ has_credits, current_user_credits_from_verify = await self.user_charging_service.verify_credits(
284
284
  user_uid,
285
285
  total_cost,
286
286
  pre_fetched_user_credits=pre_fetched_credits
@@ -300,7 +300,7 @@ class ChargingProcessor:
300
300
  }
301
301
 
302
302
  # Charge the user for all paid items
303
- charged, calculated_updated_credits = await self.charging_service.charge_credits_transaction(
303
+ charged, calculated_updated_credits = await self.user_charging_service.charge_credits_transaction(
304
304
  user_uid,
305
305
  total_cost,
306
306
  f"{operation_description} ({len(paid_items)} items, total cost: {total_cost})"
@@ -322,9 +322,9 @@ class ChargingProcessor:
322
322
 
323
323
  except ValidationError as ve:
324
324
  self.logger.error(f"Validation error during batch credit check for user {user_uid}: {str(ve)}")
325
- if self.charging_service:
325
+ if self.user_charging_service:
326
326
  try:
327
- _, current_user_credits_from_verify = await self.charging_service.verify_credits(user_uid, 0, pre_fetched_credits)
327
+ _, current_user_credits_from_verify = await self.user_charging_service.verify_credits(user_uid, 0, pre_fetched_credits)
328
328
  updated_user_credits = current_user_credits_from_verify
329
329
  except Exception: # pylint: disable=broad-except
330
330
  pass
@@ -334,9 +334,9 @@ class ChargingProcessor:
334
334
  except Exception as e:
335
335
  self.logger.error(f"Unexpected error during batch credit check for user {user_uid}: {str(e)}", exc_info=True)
336
336
  current_credits_on_error = None
337
- if self.charging_service:
337
+ if self.user_charging_service:
338
338
  try:
339
- _, current_credits_on_error = await self.charging_service.verify_credits(user_uid, 0, pre_fetched_credits)
339
+ _, current_credits_on_error = await self.user_charging_service.verify_credits(user_uid, 0, pre_fetched_credits)
340
340
  updated_user_credits = current_credits_on_error
341
341
  except Exception: # pylint: disable=broad-except
342
342
  pass
@@ -10,28 +10,8 @@ This module contains all user-related services organized into specialized operat
10
10
  - User-specific exceptions: Specialized exception classes for user operations
11
11
  """
12
12
 
13
- from .user_account_operations import UserAccountOperations
14
- from .subscription_management_operations import (
15
- SubscriptionManagementOperations,
16
- SubscriptionPlanDocument
17
- )
18
- from .iam_management_operations import IAMManagementOperations
19
- from .user_auth_operations import UserAuthOperations
20
- from .user_holistic_operations import UserHolisticOperations
21
- from .user_core_service import UserCoreService, UserTypeDefaultsDocument
22
-
23
- __all__ = [
24
- # Operation classes
25
- 'UserAccountOperations',
26
- 'SubscriptionManagementOperations',
27
- 'IAMManagementOperations',
28
- 'UserAuthOperations',
29
- 'UserHolisticOperations',
30
-
31
- # Main orchestrating service
32
- 'UserCoreService',
33
-
34
- # Supporting models
35
- 'SubscriptionPlanDocument',
36
- 'UserTypeDefaultsDocument'
37
- ]
13
+ from .user_subscription_operations import UsersubscriptionOperations
14
+ from .user_permissions_operations import UserpermissionsOperations
15
+ from .userauth_operations import UserauthOperations
16
+ from .user_multistep_operations import UsermultistepOperations
17
+ from .user_core_service import UserCoreService