# ================================================================ # services/orders/app/schemas/order_schemas.py # ================================================================ """ Order-related Pydantic schemas for Orders Service """ from datetime import datetime, date from decimal import Decimal from typing import Optional, List, Dict, Any from uuid import UUID from pydantic import BaseModel, Field, validator from app.models.enums import ( CustomerType, DeliveryMethod, PaymentTerms, PaymentMethod, PaymentStatus, CustomerSegment, PriorityLevel, OrderType, OrderStatus, OrderSource, SalesChannel, BusinessModel, ProcurementPlanType, ProcurementStrategy, RiskLevel, RequirementStatus, PlanStatus, DeliveryStatus ) # ===== Customer Schemas ===== class CustomerBase(BaseModel): name: str = Field(..., min_length=1, max_length=200) business_name: Optional[str] = Field(None, max_length=200) customer_type: CustomerType = Field(default=CustomerType.INDIVIDUAL) email: Optional[str] = Field(None, max_length=255) phone: Optional[str] = Field(None, max_length=50) address_line1: Optional[str] = Field(None, max_length=255) address_line2: Optional[str] = Field(None, max_length=255) city: Optional[str] = Field(None, max_length=100) state: Optional[str] = Field(None, max_length=100) postal_code: Optional[str] = Field(None, max_length=20) country: str = Field(default="US", max_length=100) is_active: bool = Field(default=True) preferred_delivery_method: DeliveryMethod = Field(default=DeliveryMethod.DELIVERY) payment_terms: PaymentTerms = Field(default=PaymentTerms.IMMEDIATE) credit_limit: Optional[Decimal] = Field(None, ge=0) discount_percentage: Decimal = Field(default=Decimal("0.00"), ge=0, le=100) customer_segment: CustomerSegment = Field(default=CustomerSegment.REGULAR) priority_level: PriorityLevel = Field(default=PriorityLevel.NORMAL) special_instructions: Optional[str] = None delivery_preferences: Optional[Dict[str, Any]] = None product_preferences: Optional[Dict[str, Any]] = None class Config: from_attributes = True use_enum_values = True class CustomerCreate(CustomerBase): customer_code: str = Field(..., min_length=1, max_length=50) tenant_id: UUID class CustomerUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=200) business_name: Optional[str] = Field(None, max_length=200) customer_type: Optional[CustomerType] = None email: Optional[str] = Field(None, max_length=255) phone: Optional[str] = Field(None, max_length=50) address_line1: Optional[str] = Field(None, max_length=255) address_line2: Optional[str] = Field(None, max_length=255) city: Optional[str] = Field(None, max_length=100) state: Optional[str] = Field(None, max_length=100) postal_code: Optional[str] = Field(None, max_length=20) country: Optional[str] = Field(None, max_length=100) is_active: Optional[bool] = None preferred_delivery_method: Optional[DeliveryMethod] = None payment_terms: Optional[PaymentTerms] = None credit_limit: Optional[Decimal] = Field(None, ge=0) discount_percentage: Optional[Decimal] = Field(None, ge=0, le=100) customer_segment: Optional[CustomerSegment] = None priority_level: Optional[PriorityLevel] = None special_instructions: Optional[str] = None delivery_preferences: Optional[Dict[str, Any]] = None product_preferences: Optional[Dict[str, Any]] = None class Config: from_attributes = True use_enum_values = True class CustomerResponse(CustomerBase): id: UUID tenant_id: UUID customer_code: str total_orders: int total_spent: Decimal average_order_value: Decimal last_order_date: Optional[datetime] created_at: datetime updated_at: datetime class Config: from_attributes = True # ===== Order Item Schemas ===== class OrderItemBase(BaseModel): product_id: UUID product_name: str = Field(..., min_length=1, max_length=200) product_sku: Optional[str] = Field(None, max_length=100) product_category: Optional[str] = Field(None, max_length=100) quantity: Decimal = Field(..., gt=0) unit_of_measure: str = Field(default="each", max_length=50) weight: Optional[Decimal] = Field(None, ge=0) unit_price: Decimal = Field(..., ge=0) line_discount: Decimal = Field(default=Decimal("0.00"), ge=0) product_specifications: Optional[Dict[str, Any]] = None customization_details: Optional[str] = None special_instructions: Optional[str] = None recipe_id: Optional[UUID] = None class OrderItemCreate(OrderItemBase): pass class OrderItemUpdate(BaseModel): quantity: Optional[Decimal] = Field(None, gt=0) unit_price: Optional[Decimal] = Field(None, ge=0) line_discount: Optional[Decimal] = Field(None, ge=0) product_specifications: Optional[Dict[str, Any]] = None customization_details: Optional[str] = None special_instructions: Optional[str] = None class OrderItemResponse(OrderItemBase): id: UUID order_id: UUID line_total: Decimal status: str created_at: datetime updated_at: datetime class Config: from_attributes = True # ===== Order Schemas ===== class OrderBase(BaseModel): customer_id: UUID order_type: OrderType = Field(default=OrderType.STANDARD) priority: PriorityLevel = Field(default=PriorityLevel.NORMAL) requested_delivery_date: datetime delivery_method: DeliveryMethod = Field(default=DeliveryMethod.DELIVERY) delivery_address: Optional[Dict[str, Any]] = None delivery_instructions: Optional[str] = None delivery_window_start: Optional[datetime] = None delivery_window_end: Optional[datetime] = None discount_percentage: Decimal = Field(default=Decimal("0.00"), ge=0, le=100) delivery_fee: Decimal = Field(default=Decimal("0.00"), ge=0) payment_method: Optional[PaymentMethod] = None payment_terms: PaymentTerms = Field(default=PaymentTerms.IMMEDIATE) special_instructions: Optional[str] = None custom_requirements: Optional[Dict[str, Any]] = None allergen_warnings: Optional[Dict[str, Any]] = None order_source: OrderSource = Field(default=OrderSource.MANUAL) sales_channel: SalesChannel = Field(default=SalesChannel.DIRECT) order_origin: Optional[str] = Field(None, max_length=100) communication_preferences: Optional[Dict[str, Any]] = None class Config: from_attributes = True use_enum_values = True class OrderCreate(OrderBase): tenant_id: UUID items: List[OrderItemCreate] = Field(..., min_items=1) class OrderUpdate(BaseModel): status: Optional[OrderStatus] = None priority: Optional[PriorityLevel] = None requested_delivery_date: Optional[datetime] = None confirmed_delivery_date: Optional[datetime] = None delivery_method: Optional[DeliveryMethod] = None delivery_address: Optional[Dict[str, Any]] = None delivery_instructions: Optional[str] = None delivery_window_start: Optional[datetime] = None delivery_window_end: Optional[datetime] = None payment_method: Optional[PaymentMethod] = None payment_status: Optional[PaymentStatus] = None special_instructions: Optional[str] = None custom_requirements: Optional[Dict[str, Any]] = None allergen_warnings: Optional[Dict[str, Any]] = None class Config: from_attributes = True use_enum_values = True class OrderResponse(OrderBase): id: UUID tenant_id: UUID order_number: str status: str order_date: datetime confirmed_delivery_date: Optional[datetime] actual_delivery_date: Optional[datetime] subtotal: Decimal discount_amount: Decimal tax_amount: Decimal total_amount: Decimal payment_status: str business_model: Optional[str] estimated_business_model: Optional[str] production_batch_id: Optional[UUID] quality_score: Optional[Decimal] customer_rating: Optional[int] created_at: datetime updated_at: datetime items: List[OrderItemResponse] = [] class Config: from_attributes = True # ===== Procurement Schemas ===== class ProcurementRequirementBase(BaseModel): product_id: UUID product_name: str = Field(..., min_length=1, max_length=200) product_sku: Optional[str] = Field(None, max_length=100) product_category: Optional[str] = Field(None, max_length=100) product_type: str = Field(default="ingredient") required_quantity: Decimal = Field(..., gt=0) unit_of_measure: str = Field(..., min_length=1, max_length=50) safety_stock_quantity: Decimal = Field(default=Decimal("0.000"), ge=0) required_by_date: date priority: PriorityLevel = Field(default=PriorityLevel.NORMAL) preferred_supplier_id: Optional[UUID] = None quality_specifications: Optional[Dict[str, Any]] = None special_requirements: Optional[str] = None storage_requirements: Optional[str] = Field(None, max_length=200) class Config: from_attributes = True use_enum_values = True class ProcurementRequirementCreate(ProcurementRequirementBase): pass class ProcurementRequirementResponse(ProcurementRequirementBase): id: UUID plan_id: UUID requirement_number: str total_quantity_needed: Decimal current_stock_level: Decimal available_stock: Decimal net_requirement: Decimal order_demand: Decimal production_demand: Decimal forecast_demand: Decimal status: str estimated_unit_cost: Optional[Decimal] estimated_total_cost: Optional[Decimal] supplier_name: Optional[str] created_at: datetime updated_at: datetime class Config: from_attributes = True class ProcurementPlanBase(BaseModel): plan_date: date plan_period_start: date plan_period_end: date planning_horizon_days: int = Field(default=14, ge=1, le=365) plan_type: ProcurementPlanType = Field(default=ProcurementPlanType.REGULAR) priority: PriorityLevel = Field(default=PriorityLevel.NORMAL) business_model: Optional[BusinessModel] = None procurement_strategy: ProcurementStrategy = Field(default=ProcurementStrategy.JUST_IN_TIME) safety_stock_buffer: Decimal = Field(default=Decimal("20.00"), ge=0, le=100) special_requirements: Optional[str] = None class Config: from_attributes = True use_enum_values = True class ProcurementPlanCreate(ProcurementPlanBase): tenant_id: UUID requirements: List[ProcurementRequirementCreate] = Field(..., min_items=1) class ProcurementPlanResponse(ProcurementPlanBase): id: UUID tenant_id: UUID plan_number: str status: str total_requirements: int total_estimated_cost: Decimal total_approved_cost: Decimal total_demand_orders: int supply_risk_level: str approved_at: Optional[datetime] created_at: datetime updated_at: datetime requirements: List[ProcurementRequirementResponse] = [] class Config: from_attributes = True # ===== Dashboard and Analytics Schemas ===== class OrdersDashboardSummary(BaseModel): """Summary data for orders dashboard""" # Current period metrics total_orders_today: int total_orders_this_week: int total_orders_this_month: int # Revenue metrics revenue_today: Decimal revenue_this_week: Decimal revenue_this_month: Decimal # Order status breakdown pending_orders: int confirmed_orders: int in_production_orders: int ready_orders: int delivered_orders: int # Customer metrics total_customers: int new_customers_this_month: int repeat_customers_rate: Decimal # Performance metrics average_order_value: Decimal order_fulfillment_rate: Decimal on_time_delivery_rate: Decimal # Business model detection business_model: Optional[str] business_model_confidence: Optional[Decimal] # Recent activity recent_orders: List[OrderResponse] high_priority_orders: List[OrderResponse] class DemandRequirements(BaseModel): """Demand requirements for production planning""" date: date tenant_id: UUID # Product demand breakdown product_demands: List[Dict[str, Any]] # Aggregate metrics total_orders: int total_quantity: Decimal total_value: Decimal # Business context business_model: Optional[str] rush_orders_count: int special_requirements: List[str] # Timing requirements earliest_delivery: datetime latest_delivery: datetime average_lead_time_hours: int class ProcurementPlanningData(BaseModel): """Data for procurement planning decisions""" planning_date: date planning_horizon_days: int # Demand forecast demand_forecast: List[Dict[str, Any]] # Current inventory status inventory_levels: Dict[str, Any] # Supplier information supplier_performance: Dict[str, Any] # Risk factors supply_risks: List[str] demand_volatility: Decimal # Recommendations recommended_purchases: List[Dict[str, Any]] critical_shortages: List[Dict[str, Any]]