VanithaSivaraj commited on
Commit
c0cc858
·
1 Parent(s): a326f69

(catalogues): implement global meta schema for catalogues module with audit information

Browse files
app/catalogues/controllers/router.py CHANGED
@@ -320,6 +320,7 @@ async def update_item(
320
  catalogue_id,
321
  update_data,
322
  current_user.user_id,
 
323
  merchant_id=current_user.merchant_id
324
  )
325
 
 
320
  catalogue_id,
321
  update_data,
322
  current_user.user_id,
323
+ current_user.username,
324
  merchant_id=current_user.merchant_id
325
  )
326
 
app/catalogues/schemas/schema.py CHANGED
@@ -732,7 +732,16 @@ class Catalogue(BaseModel):
732
  inventory: Optional[Inventory] = Field(None, description="Inventory management configuration")
733
  tax: Optional[Tax] = Field(None, description="Tax information (HSN, GST)")
734
  media: Optional[Media] = Field(None, description="Product images and media")
735
- meta: Optional[Meta] = Field(None, description="Metadata (timestamps, status, created by)")
 
 
 
 
 
 
 
 
 
736
 
737
  @field_validator("catalogue_code")
738
  def validate_catalogue_code(cls, v):
 
732
  inventory: Optional[Inventory] = Field(None, description="Inventory management configuration")
733
  tax: Optional[Tax] = Field(None, description="Tax information (HSN, GST)")
734
  media: Optional[Media] = Field(None, description="Product images and media")
735
+ created_by: Optional[constr(min_length=3, max_length=100, strip_whitespace=True)] = Field(
736
+ None,
737
+ description="User ID of the creator of this catalogue item"
738
+ )
739
+ updated_by: Optional[constr(min_length=3, max_length=100, strip_whitespace=True)] = Field(None, description="User ID of the last updater of this catalogue item")
740
+ updated_at: Optional[datetime] = Field(None, description="Last update timestamp")
741
+ created_at: Optional[datetime] = Field(None, description="Timestamp of creation")
742
+ created_by_username: Optional[constr(min_length=3, max_length=100, strip_whitespace=True)] = Field(None, description="Username of the creator of this catalogue item")
743
+ updated_by_username: Optional[constr(min_length=3, max_length=100, strip_whitespace=True)] = Field(None, description="Username of the creator of this catalogue item")
744
+ status: CatalogueStatus = Field(CatalogueStatus.ACTIVE, description="Status of the catalogue item")
745
 
746
  @field_validator("catalogue_code")
747
  def validate_catalogue_code(cls, v):
app/catalogues/services/service.py CHANGED
@@ -7,6 +7,7 @@ from fastapi import HTTPException, status
7
  from motor.core import AgnosticDatabase as AsyncIOMotorDatabase
8
  from app.catalogues.schemas.schema import Catalogue
9
  from app.catalogues.constants import SCM_CATALOGUE_COLLECTION
 
10
  from app.dependencies.auth import TokenUser
11
  from app.utils.util import flatten_update_data
12
  from app.catalogues.utils import (
@@ -227,7 +228,22 @@ class CatalogueService:
227
 
228
  items = []
229
  async for doc in cursor:
230
- items.append(doc if projection_list else Catalogue(**doc))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
 
232
  return items, total_count
233
 
@@ -351,13 +367,13 @@ class CatalogueService:
351
  inventory=data.inventory,
352
  tax=data.tax,
353
  media=data.media,
354
-
355
- meta={
356
- "created_by": current_user.user_id,
357
- "created_by_user_name": current_user.username,
358
- "created_at": datetime.utcnow(),
359
- "status": "Active",
360
- }
361
  )
362
 
363
  # Insert into MongoDB
@@ -384,7 +400,7 @@ class CatalogueService:
384
  detail="Failed to create catalogue item"
385
  )
386
 
387
- async def update_catalogue_item(self, catalogue_id: str, update_data: dict, updated_by: str, merchant_id: str = None):
388
  """Update an existing catalogue item with merchant filtering."""
389
  try:
390
  # Check if the catalogue exists with merchant filtering
@@ -439,8 +455,9 @@ class CatalogueService:
439
  update_data_flat = flatten_update_data(update_data)
440
 
441
  # Add metadata
442
- update_data_flat["meta.updated_by"] = updated_by
443
- update_data_flat["meta.updated_at"] = datetime.utcnow()
 
444
 
445
  # Update MongoDB with merchant filtering
446
  update_query = {"catalogue_id": catalogue_id}
@@ -693,7 +710,9 @@ class CatalogueService:
693
  if projection_list:
694
  return doc
695
  else:
696
- return Catalogue(**doc)
 
 
697
 
698
  except HTTPException:
699
  raise
@@ -877,6 +896,7 @@ class CatalogueService:
877
  cr.barcode_number,
878
  cr.hsn_code,
879
  cr.gst_rate,
 
880
  cr.mrp,
881
  COALESCE(cp.cost_price, cr.base_price) AS cost_price,
882
  COALESCE(cp.trade_margin, 0) AS trade_margin,
@@ -1000,17 +1020,18 @@ class CatalogueService:
1000
  "lead_time_days": int(row.lead_time_days) if row.lead_time_days is not None else 7,
1001
  "max_stock_level": int(row.max_stock_level) if row.max_stock_level is not None else 1000,
1002
  "unit": row.unit if row.unit else "PCS",
 
1003
  }
1004
-
1005
  # Apply projection if specified
1006
  if projection_list:
1007
  projected_item = {}
1008
  for field in projection_list:
1009
- if field in row_dict:
1010
- projected_item[field] = row_dict[field]
1011
  items.append(projected_item)
1012
  else:
1013
- items.append(row_dict)
1014
 
1015
  logger.info(f"Retrieved {len(items)} merchant catalogue items for merchant {merchant_id}")
1016
  return items, total_count
 
7
  from motor.core import AgnosticDatabase as AsyncIOMotorDatabase
8
  from app.catalogues.schemas.schema import Catalogue
9
  from app.catalogues.constants import SCM_CATALOGUE_COLLECTION
10
+ from app.core.utils import format_meta_field
11
  from app.dependencies.auth import TokenUser
12
  from app.utils.util import flatten_update_data
13
  from app.catalogues.utils import (
 
228
 
229
  items = []
230
  async for doc in cursor:
231
+ if projection_list:
232
+ # Projection returns raw dict → format directly
233
+ formatted_doc = format_meta_field(doc)
234
+ items.append(formatted_doc)
235
+
236
+ else:
237
+ # Create Pydantic model first
238
+ catalogue_obj = Catalogue(**doc)
239
+
240
+ # Convert to dict
241
+ catalogue_dict = catalogue_obj.model_dump()
242
+
243
+ # Apply formatting AFTER model creation
244
+ formatted_doc = format_meta_field(catalogue_dict)
245
+
246
+ items.append(formatted_doc)
247
 
248
  return items, total_count
249
 
 
367
  inventory=data.inventory,
368
  tax=data.tax,
369
  media=data.media,
370
+ created_by=current_user.user_id,
371
+ created_by_username=current_user.username,
372
+ created_at=datetime.utcnow(),
373
+ updated_at=None,
374
+ updated_by_username=None,
375
+ updated_by=None,
376
+ status="Active",
377
  )
378
 
379
  # Insert into MongoDB
 
400
  detail="Failed to create catalogue item"
401
  )
402
 
403
+ async def update_catalogue_item(self, catalogue_id: str, update_data: dict, updated_by: str, updated_by_username: str, merchant_id: str = None):
404
  """Update an existing catalogue item with merchant filtering."""
405
  try:
406
  # Check if the catalogue exists with merchant filtering
 
455
  update_data_flat = flatten_update_data(update_data)
456
 
457
  # Add metadata
458
+ update_data_flat["updated_by"] = updated_by
459
+ update_data_flat["updated_by_username"] = updated_by_username
460
+ update_data_flat["updated_at"] = datetime.utcnow()
461
 
462
  # Update MongoDB with merchant filtering
463
  update_query = {"catalogue_id": catalogue_id}
 
710
  if projection_list:
711
  return doc
712
  else:
713
+ data = Catalogue(**doc)
714
+ formatted_data = format_meta_field(data.model_dump())
715
+ return formatted_data
716
 
717
  except HTTPException:
718
  raise
 
896
  cr.barcode_number,
897
  cr.hsn_code,
898
  cr.gst_rate,
899
+ cr.updated_at,
900
  cr.mrp,
901
  COALESCE(cp.cost_price, cr.base_price) AS cost_price,
902
  COALESCE(cp.trade_margin, 0) AS trade_margin,
 
1020
  "lead_time_days": int(row.lead_time_days) if row.lead_time_days is not None else 7,
1021
  "max_stock_level": int(row.max_stock_level) if row.max_stock_level is not None else 1000,
1022
  "unit": row.unit if row.unit else "PCS",
1023
+ "updated_at": row.updated_at
1024
  }
1025
+ formatted_item = format_meta_field(row_dict)
1026
  # Apply projection if specified
1027
  if projection_list:
1028
  projected_item = {}
1029
  for field in projection_list:
1030
+ if field in formatted_item:
1031
+ projected_item[field] = formatted_item[field]
1032
  items.append(projected_item)
1033
  else:
1034
+ items.append(formatted_item)
1035
 
1036
  logger.info(f"Retrieved {len(items)} merchant catalogue items for merchant {merchant_id}")
1037
  return items, total_count