Files
bakery-ia/services/forecasting/app/models/forecasts.py

102 lines
3.9 KiB
Python
Raw Normal View History

2025-07-21 19:48:56 +02:00
# ================================================================
# services/forecasting/app/models/forecasts.py
# ================================================================
"""
Forecast models for the forecasting service
"""
2025-11-15 15:20:10 +01:00
from sqlalchemy import Column, String, Integer, Float, DateTime, Boolean, Text, JSON, UniqueConstraint, Index
2025-07-21 19:48:56 +02:00
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"
2025-11-15 15:20:10 +01:00
__table_args__ = (
# Unique constraint to prevent duplicate forecasts
# Ensures only one forecast per (tenant, product, date, location) combination
UniqueConstraint(
'tenant_id', 'inventory_product_id', 'forecast_date', 'location',
name='uq_forecast_tenant_product_date_location'
),
# Composite index for common query patterns
Index('ix_forecasts_tenant_product_date', 'tenant_id', 'inventory_product_id', 'forecast_date'),
)
2025-07-21 19:48:56 +02:00
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
2025-08-14 16:47:34 +02:00
inventory_product_id = Column(UUID(as_uuid=True), nullable=False, index=True) # Reference to inventory service
product_name = Column(String(255), nullable=True, index=True) # Product name (optional - use inventory_product_id as reference)
2025-07-21 19:48:56 +02:00
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
2025-07-30 09:35:01 +02:00
model_id = Column(String(255), nullable=False)
2025-07-21 19:48:56 +02:00
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):
2025-08-14 16:47:34 +02:00
return f"<Forecast(id={self.id}, inventory_product_id={self.inventory_product_id}, date={self.forecast_date})>"
2025-07-21 19:48:56 +02:00
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)
2025-08-02 17:09:53 +02:00
cancelled_by = Column(String, nullable=True)
2025-07-21 19:48:56 +02:00
def __repr__(self):
return f"<PredictionBatch(id={self.id}, status={self.status})>"