Files
bakery-ia/services/forecasting/app/models/forecasts.py
2025-08-02 17:09:53 +02:00

115 lines
4.3 KiB
Python

# ================================================================
# services/forecasting/app/models/forecasts.py
# ================================================================
"""
Forecast models for the forecasting service
"""
from sqlalchemy import Column, String, Integer, Float, DateTime, Boolean, Text, JSON
from sqlalchemy.dialects.postgresql import UUID
from datetime import datetime, timezone
import uuid
from shared.database.base import Base
class Forecast(Base):
"""Forecast model for storing prediction results"""
__tablename__ = "forecasts"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
product_name = Column(String(255), nullable=False, index=True)
location = Column(String(255), nullable=False, index=True)
# Forecast period
forecast_date = Column(DateTime(timezone=True), nullable=False, index=True)
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
# Prediction results
predicted_demand = Column(Float, nullable=False)
confidence_lower = Column(Float, nullable=False)
confidence_upper = Column(Float, nullable=False)
confidence_level = Column(Float, default=0.8)
# Model information
model_id = Column(String(255), nullable=False)
model_version = Column(String(50), nullable=False)
algorithm = Column(String(50), default="prophet")
# Business context
business_type = Column(String(50), default="individual") # individual or central_workshop
day_of_week = Column(Integer, nullable=False)
is_holiday = Column(Boolean, default=False)
is_weekend = Column(Boolean, default=False)
# External factors
weather_temperature = Column(Float)
weather_precipitation = Column(Float)
weather_description = Column(String(100))
traffic_volume = Column(Integer)
# Metadata
processing_time_ms = Column(Integer)
features_used = Column(JSON)
def __repr__(self):
return f"<Forecast(id={self.id}, product={self.product_name}, date={self.forecast_date})>"
class PredictionBatch(Base):
"""Batch prediction requests"""
__tablename__ = "prediction_batches"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
# Batch information
batch_name = Column(String(255), nullable=False)
requested_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
completed_at = Column(DateTime(timezone=True))
# Status
status = Column(String(50), default="pending") # pending, processing, completed, failed
total_products = Column(Integer, default=0)
completed_products = Column(Integer, default=0)
failed_products = Column(Integer, default=0)
# Configuration
forecast_days = Column(Integer, default=7)
business_type = Column(String(50), default="individual")
# Results
error_message = Column(Text)
processing_time_ms = Column(Integer)
cancelled_by = Column(String, nullable=True)
def __repr__(self):
return f"<PredictionBatch(id={self.id}, status={self.status})>"
class ForecastAlert(Base):
"""Alerts based on forecast results"""
__tablename__ = "forecast_alerts"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
forecast_id = Column(UUID(as_uuid=True), nullable=False)
# Alert information
alert_type = Column(String(50), nullable=False) # high_demand, low_demand, stockout_risk
severity = Column(String(20), default="medium") # low, medium, high, critical
message = Column(Text, nullable=False)
# Status
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
acknowledged_at = Column(DateTime(timezone=True))
resolved_at = Column(DateTime(timezone=True))
is_active = Column(Boolean, default=True)
# Notification
notification_sent = Column(Boolean, default=False)
notification_method = Column(String(50)) # email, whatsapp, sms
def __repr__(self):
return f"<ForecastAlert(id={self.id}, type={self.alert_type})>"