demo seed change

This commit is contained in:
Urtzi Alfaro
2025-12-13 23:57:54 +01:00
parent f3688dfb04
commit ff830a3415
299 changed files with 20328 additions and 19485 deletions

View File

@@ -148,6 +148,107 @@ class EventRepository:
result = await self.session.execute(query)
return result.scalar_one_or_none()
async def check_duplicate_alert(self, tenant_id: UUID, event_type: str, entity_links: Dict, event_metadata: Dict, time_window_hours: int = 24) -> Optional[Event]:
"""
Check if a similar alert already exists within the time window.
Args:
tenant_id: Tenant UUID
event_type: Type of event (e.g., 'production_delay', 'critical_stock_shortage')
entity_links: Entity references (e.g., batch_id, po_id, ingredient_id)
event_metadata: Event metadata for comparison
time_window_hours: Time window in hours to check for duplicates
Returns:
Existing event if duplicate found, None otherwise
"""
from datetime import datetime, timedelta, timezone
# Calculate time threshold
time_threshold = datetime.now(timezone.utc) - timedelta(hours=time_window_hours)
# Build query to find potential duplicates
query = select(Event).where(
and_(
Event.tenant_id == tenant_id,
Event.event_type == event_type,
Event.status == "active", # Only check active alerts
Event.created_at >= time_threshold
)
)
result = await self.session.execute(query)
potential_duplicates = result.scalars().all()
# Compare each potential duplicate for semantic similarity
for event in potential_duplicates:
# Check if entity links match (same batch, PO, ingredient, etc.)
if self._entities_match(event.entity_links, entity_links):
# For production delays, check if it's the same batch with similar delay
if event_type == "production_delay":
if self._production_delay_match(event.event_metadata, event_metadata):
return event
# For critical stock shortages, check if it's the same ingredient
elif event_type == "critical_stock_shortage":
if self._stock_shortage_match(event.event_metadata, event_metadata):
return event
# For delivery overdue alerts, check if it's the same PO
elif event_type == "delivery_overdue":
if self._delivery_overdue_match(event.event_metadata, event_metadata):
return event
# For general matching based on metadata
else:
if self._metadata_match(event.event_metadata, event_metadata):
return event
return None
def _entities_match(self, existing_links: Dict, new_links: Dict) -> bool:
"""Check if entity links match between two events."""
if not existing_links or not new_links:
return False
# Check for common entity types
common_entities = ['production_batch', 'purchase_order', 'ingredient', 'supplier', 'equipment']
for entity in common_entities:
if entity in existing_links and entity in new_links:
if existing_links[entity] == new_links[entity]:
return True
return False
def _production_delay_match(self, existing_meta: Dict, new_meta: Dict) -> bool:
"""Check if production delay alerts match."""
# Same batch_id indicates same production issue
return (existing_meta.get('batch_id') == new_meta.get('batch_id') and
existing_meta.get('product_name') == new_meta.get('product_name'))
def _stock_shortage_match(self, existing_meta: Dict, new_meta: Dict) -> bool:
"""Check if stock shortage alerts match."""
# Same ingredient_id indicates same shortage issue
return existing_meta.get('ingredient_id') == new_meta.get('ingredient_id')
def _delivery_overdue_match(self, existing_meta: Dict, new_meta: Dict) -> bool:
"""Check if delivery overdue alerts match."""
# Same PO indicates same delivery issue
return existing_meta.get('po_id') == new_meta.get('po_id')
def _metadata_match(self, existing_meta: Dict, new_meta: Dict) -> bool:
"""Generic metadata matching for other alert types."""
# Check for common identifying fields
common_fields = ['batch_id', 'po_id', 'ingredient_id', 'supplier_id', 'equipment_id']
for field in common_fields:
if field in existing_meta and field in new_meta:
if existing_meta[field] == new_meta[field]:
return True
return False
async def get_summary(self, tenant_id: UUID) -> EventSummary:
"""
Get summary statistics for dashboard.