2025-07-21 19:48:56 +02:00
|
|
|
# ================================================================
|
|
|
|
|
# services/forecasting/app/schemas/forecasts.py
|
|
|
|
|
# ================================================================
|
|
|
|
|
"""
|
|
|
|
|
Forecast schemas for request/response validation
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from pydantic import BaseModel, Field, validator
|
|
|
|
|
from datetime import datetime, date
|
|
|
|
|
from typing import Optional, List, Dict, Any
|
|
|
|
|
from enum import Enum
|
|
|
|
|
|
|
|
|
|
class BusinessType(str, Enum):
|
|
|
|
|
INDIVIDUAL = "individual"
|
|
|
|
|
CENTRAL_WORKSHOP = "central_workshop"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForecastRequest(BaseModel):
|
|
|
|
|
"""Request schema for generating forecasts"""
|
2025-08-14 16:47:34 +02:00
|
|
|
inventory_product_id: str = Field(..., description="Inventory product UUID reference")
|
|
|
|
|
# product_name: str = Field(..., description="Product name") # DEPRECATED - use inventory_product_id
|
2025-07-29 17:24:56 +02:00
|
|
|
forecast_date: date = Field(..., description="Starting date for forecast")
|
|
|
|
|
forecast_days: int = Field(1, ge=1, le=30, description="Number of days to forecast")
|
|
|
|
|
location: str = Field(..., description="Location identifier")
|
|
|
|
|
|
|
|
|
|
# Optional parameters - internally handled
|
|
|
|
|
confidence_level: float = Field(0.8, ge=0.5, le=0.95, description="Confidence level")
|
2025-07-21 19:48:56 +02:00
|
|
|
|
|
|
|
|
@validator('forecast_date')
|
|
|
|
|
def validate_forecast_date(cls, v):
|
|
|
|
|
if v < date.today():
|
|
|
|
|
raise ValueError("Forecast date cannot be in the past")
|
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
class BatchForecastRequest(BaseModel):
|
|
|
|
|
"""Request schema for batch forecasting"""
|
|
|
|
|
tenant_id: str = Field(..., description="Tenant ID")
|
|
|
|
|
batch_name: str = Field(..., description="Batch name for tracking")
|
2025-08-14 16:47:34 +02:00
|
|
|
inventory_product_ids: List[str] = Field(..., description="List of inventory product IDs")
|
2025-07-21 19:48:56 +02:00
|
|
|
forecast_days: int = Field(7, ge=1, le=30, description="Number of days to forecast")
|
|
|
|
|
|
|
|
|
|
class ForecastResponse(BaseModel):
|
|
|
|
|
"""Response schema for forecast results"""
|
|
|
|
|
id: str
|
|
|
|
|
tenant_id: str
|
2025-08-14 16:47:34 +02:00
|
|
|
inventory_product_id: str # Reference to inventory service
|
|
|
|
|
# product_name: str # Can be fetched from inventory service if needed for display
|
2025-07-21 19:48:56 +02:00
|
|
|
location: str
|
|
|
|
|
forecast_date: datetime
|
|
|
|
|
|
|
|
|
|
# Predictions
|
|
|
|
|
predicted_demand: float
|
|
|
|
|
confidence_lower: float
|
|
|
|
|
confidence_upper: float
|
|
|
|
|
confidence_level: float
|
|
|
|
|
|
|
|
|
|
# Model info
|
|
|
|
|
model_id: str
|
|
|
|
|
model_version: str
|
|
|
|
|
algorithm: str
|
|
|
|
|
|
|
|
|
|
# Context
|
|
|
|
|
business_type: str
|
|
|
|
|
is_holiday: bool
|
|
|
|
|
is_weekend: bool
|
|
|
|
|
day_of_week: int
|
|
|
|
|
|
|
|
|
|
# External factors
|
|
|
|
|
weather_temperature: Optional[float]
|
|
|
|
|
weather_precipitation: Optional[float]
|
|
|
|
|
weather_description: Optional[str]
|
|
|
|
|
traffic_volume: Optional[int]
|
|
|
|
|
|
|
|
|
|
# Metadata
|
|
|
|
|
created_at: datetime
|
|
|
|
|
processing_time_ms: Optional[int]
|
|
|
|
|
features_used: Optional[Dict[str, Any]]
|
|
|
|
|
|
|
|
|
|
class BatchForecastResponse(BaseModel):
|
|
|
|
|
"""Response schema for batch forecast requests"""
|
|
|
|
|
id: str
|
|
|
|
|
tenant_id: str
|
|
|
|
|
batch_name: str
|
|
|
|
|
status: str
|
|
|
|
|
total_products: int
|
|
|
|
|
completed_products: int
|
|
|
|
|
failed_products: int
|
|
|
|
|
|
|
|
|
|
# Timing
|
|
|
|
|
requested_at: datetime
|
|
|
|
|
completed_at: Optional[datetime]
|
|
|
|
|
processing_time_ms: Optional[int]
|
|
|
|
|
|
|
|
|
|
# Results
|
|
|
|
|
forecasts: Optional[List[ForecastResponse]]
|
|
|
|
|
error_message: Optional[str]
|
|
|
|
|
|
|
|
|
|
|