257 lines
9.7 KiB
Python
257 lines
9.7 KiB
Python
|
|
# services/recipes/app/schemas/production.py
|
||
|
|
"""
|
||
|
|
Pydantic schemas for production-related API requests and responses
|
||
|
|
"""
|
||
|
|
|
||
|
|
from pydantic import BaseModel, Field
|
||
|
|
from typing import List, Optional, Dict, Any
|
||
|
|
from uuid import UUID
|
||
|
|
from datetime import datetime, date
|
||
|
|
from enum import Enum
|
||
|
|
|
||
|
|
from ..models.recipes import ProductionStatus, ProductionPriority, MeasurementUnit
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionIngredientConsumptionCreate(BaseModel):
|
||
|
|
"""Schema for creating production ingredient consumption"""
|
||
|
|
recipe_ingredient_id: UUID
|
||
|
|
ingredient_id: UUID
|
||
|
|
stock_id: Optional[UUID] = None
|
||
|
|
planned_quantity: float = Field(..., gt=0)
|
||
|
|
actual_quantity: float = Field(..., gt=0)
|
||
|
|
unit: MeasurementUnit
|
||
|
|
consumption_notes: Optional[str] = None
|
||
|
|
staff_member: Optional[UUID] = None
|
||
|
|
ingredient_condition: Optional[str] = None
|
||
|
|
quality_impact: Optional[str] = None
|
||
|
|
substitution_used: bool = False
|
||
|
|
substitution_details: Optional[str] = None
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionIngredientConsumptionResponse(BaseModel):
|
||
|
|
"""Schema for production ingredient consumption responses"""
|
||
|
|
id: UUID
|
||
|
|
tenant_id: UUID
|
||
|
|
production_batch_id: UUID
|
||
|
|
recipe_ingredient_id: UUID
|
||
|
|
ingredient_id: UUID
|
||
|
|
stock_id: Optional[UUID] = None
|
||
|
|
planned_quantity: float
|
||
|
|
actual_quantity: float
|
||
|
|
unit: str
|
||
|
|
variance_quantity: Optional[float] = None
|
||
|
|
variance_percentage: Optional[float] = None
|
||
|
|
unit_cost: Optional[float] = None
|
||
|
|
total_cost: Optional[float] = None
|
||
|
|
consumption_time: datetime
|
||
|
|
consumption_notes: Optional[str] = None
|
||
|
|
staff_member: Optional[UUID] = None
|
||
|
|
ingredient_condition: Optional[str] = None
|
||
|
|
quality_impact: Optional[str] = None
|
||
|
|
substitution_used: bool
|
||
|
|
substitution_details: Optional[str] = None
|
||
|
|
|
||
|
|
class Config:
|
||
|
|
from_attributes = True
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionBatchCreate(BaseModel):
|
||
|
|
"""Schema for creating production batches"""
|
||
|
|
recipe_id: UUID
|
||
|
|
batch_number: str = Field(..., min_length=1, max_length=100)
|
||
|
|
production_date: date
|
||
|
|
planned_start_time: Optional[datetime] = None
|
||
|
|
planned_end_time: Optional[datetime] = None
|
||
|
|
planned_quantity: float = Field(..., gt=0)
|
||
|
|
batch_size_multiplier: float = Field(default=1.0, gt=0)
|
||
|
|
priority: ProductionPriority = ProductionPriority.NORMAL
|
||
|
|
assigned_staff: Optional[List[UUID]] = None
|
||
|
|
production_notes: Optional[str] = None
|
||
|
|
customer_order_reference: Optional[str] = None
|
||
|
|
pre_order_quantity: Optional[float] = Field(None, ge=0)
|
||
|
|
shelf_quantity: Optional[float] = Field(None, ge=0)
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionBatchUpdate(BaseModel):
|
||
|
|
"""Schema for updating production batches"""
|
||
|
|
batch_number: Optional[str] = Field(None, min_length=1, max_length=100)
|
||
|
|
production_date: Optional[date] = None
|
||
|
|
planned_start_time: Optional[datetime] = None
|
||
|
|
actual_start_time: Optional[datetime] = None
|
||
|
|
planned_end_time: Optional[datetime] = None
|
||
|
|
actual_end_time: Optional[datetime] = None
|
||
|
|
planned_quantity: Optional[float] = Field(None, gt=0)
|
||
|
|
actual_quantity: Optional[float] = Field(None, ge=0)
|
||
|
|
batch_size_multiplier: Optional[float] = Field(None, gt=0)
|
||
|
|
status: Optional[ProductionStatus] = None
|
||
|
|
priority: Optional[ProductionPriority] = None
|
||
|
|
assigned_staff: Optional[List[UUID]] = None
|
||
|
|
production_notes: Optional[str] = None
|
||
|
|
quality_score: Optional[float] = Field(None, ge=1, le=10)
|
||
|
|
quality_notes: Optional[str] = None
|
||
|
|
defect_rate: Optional[float] = Field(None, ge=0, le=100)
|
||
|
|
rework_required: Optional[bool] = None
|
||
|
|
labor_cost: Optional[float] = Field(None, ge=0)
|
||
|
|
overhead_cost: Optional[float] = Field(None, ge=0)
|
||
|
|
production_temperature: Optional[float] = None
|
||
|
|
production_humidity: Optional[float] = Field(None, ge=0, le=100)
|
||
|
|
oven_temperature: Optional[float] = None
|
||
|
|
baking_time_minutes: Optional[int] = Field(None, ge=0)
|
||
|
|
waste_quantity: Optional[float] = Field(None, ge=0)
|
||
|
|
waste_reason: Optional[str] = None
|
||
|
|
customer_order_reference: Optional[str] = None
|
||
|
|
pre_order_quantity: Optional[float] = Field(None, ge=0)
|
||
|
|
shelf_quantity: Optional[float] = Field(None, ge=0)
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionBatchResponse(BaseModel):
|
||
|
|
"""Schema for production batch responses"""
|
||
|
|
id: UUID
|
||
|
|
tenant_id: UUID
|
||
|
|
recipe_id: UUID
|
||
|
|
batch_number: str
|
||
|
|
production_date: date
|
||
|
|
planned_start_time: Optional[datetime] = None
|
||
|
|
actual_start_time: Optional[datetime] = None
|
||
|
|
planned_end_time: Optional[datetime] = None
|
||
|
|
actual_end_time: Optional[datetime] = None
|
||
|
|
planned_quantity: float
|
||
|
|
actual_quantity: Optional[float] = None
|
||
|
|
yield_percentage: Optional[float] = None
|
||
|
|
batch_size_multiplier: float
|
||
|
|
status: str
|
||
|
|
priority: str
|
||
|
|
assigned_staff: Optional[List[UUID]] = None
|
||
|
|
production_notes: Optional[str] = None
|
||
|
|
quality_score: Optional[float] = None
|
||
|
|
quality_notes: Optional[str] = None
|
||
|
|
defect_rate: Optional[float] = None
|
||
|
|
rework_required: bool
|
||
|
|
planned_material_cost: Optional[float] = None
|
||
|
|
actual_material_cost: Optional[float] = None
|
||
|
|
labor_cost: Optional[float] = None
|
||
|
|
overhead_cost: Optional[float] = None
|
||
|
|
total_production_cost: Optional[float] = None
|
||
|
|
cost_per_unit: Optional[float] = None
|
||
|
|
production_temperature: Optional[float] = None
|
||
|
|
production_humidity: Optional[float] = None
|
||
|
|
oven_temperature: Optional[float] = None
|
||
|
|
baking_time_minutes: Optional[int] = None
|
||
|
|
waste_quantity: float
|
||
|
|
waste_reason: Optional[str] = None
|
||
|
|
efficiency_percentage: Optional[float] = None
|
||
|
|
customer_order_reference: Optional[str] = None
|
||
|
|
pre_order_quantity: Optional[float] = None
|
||
|
|
shelf_quantity: Optional[float] = None
|
||
|
|
created_at: datetime
|
||
|
|
updated_at: datetime
|
||
|
|
created_by: Optional[UUID] = None
|
||
|
|
completed_by: Optional[UUID] = None
|
||
|
|
ingredient_consumptions: Optional[List[ProductionIngredientConsumptionResponse]] = None
|
||
|
|
|
||
|
|
class Config:
|
||
|
|
from_attributes = True
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionBatchSearchRequest(BaseModel):
|
||
|
|
"""Schema for production batch search requests"""
|
||
|
|
search_term: Optional[str] = None
|
||
|
|
status: Optional[ProductionStatus] = None
|
||
|
|
priority: Optional[ProductionPriority] = None
|
||
|
|
start_date: Optional[date] = None
|
||
|
|
end_date: Optional[date] = None
|
||
|
|
recipe_id: Optional[UUID] = None
|
||
|
|
limit: int = Field(default=100, ge=1, le=1000)
|
||
|
|
offset: int = Field(default=0, ge=0)
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionScheduleCreate(BaseModel):
|
||
|
|
"""Schema for creating production schedules"""
|
||
|
|
schedule_date: date
|
||
|
|
schedule_name: Optional[str] = Field(None, max_length=255)
|
||
|
|
estimated_production_hours: Optional[float] = Field(None, gt=0)
|
||
|
|
estimated_material_cost: Optional[float] = Field(None, ge=0)
|
||
|
|
available_staff_hours: Optional[float] = Field(None, gt=0)
|
||
|
|
oven_capacity_hours: Optional[float] = Field(None, gt=0)
|
||
|
|
production_capacity_limit: Optional[float] = Field(None, gt=0)
|
||
|
|
schedule_notes: Optional[str] = None
|
||
|
|
preparation_instructions: Optional[str] = None
|
||
|
|
special_requirements: Optional[Dict[str, Any]] = None
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionScheduleUpdate(BaseModel):
|
||
|
|
"""Schema for updating production schedules"""
|
||
|
|
schedule_name: Optional[str] = Field(None, max_length=255)
|
||
|
|
total_planned_batches: Optional[int] = Field(None, ge=0)
|
||
|
|
total_planned_items: Optional[float] = Field(None, ge=0)
|
||
|
|
estimated_production_hours: Optional[float] = Field(None, gt=0)
|
||
|
|
estimated_material_cost: Optional[float] = Field(None, ge=0)
|
||
|
|
is_published: Optional[bool] = None
|
||
|
|
is_completed: Optional[bool] = None
|
||
|
|
completion_percentage: Optional[float] = Field(None, ge=0, le=100)
|
||
|
|
available_staff_hours: Optional[float] = Field(None, gt=0)
|
||
|
|
oven_capacity_hours: Optional[float] = Field(None, gt=0)
|
||
|
|
production_capacity_limit: Optional[float] = Field(None, gt=0)
|
||
|
|
schedule_notes: Optional[str] = None
|
||
|
|
preparation_instructions: Optional[str] = None
|
||
|
|
special_requirements: Optional[Dict[str, Any]] = None
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionScheduleResponse(BaseModel):
|
||
|
|
"""Schema for production schedule responses"""
|
||
|
|
id: UUID
|
||
|
|
tenant_id: UUID
|
||
|
|
schedule_date: date
|
||
|
|
schedule_name: Optional[str] = None
|
||
|
|
total_planned_batches: int
|
||
|
|
total_planned_items: float
|
||
|
|
estimated_production_hours: Optional[float] = None
|
||
|
|
estimated_material_cost: Optional[float] = None
|
||
|
|
is_published: bool
|
||
|
|
is_completed: bool
|
||
|
|
completion_percentage: Optional[float] = None
|
||
|
|
available_staff_hours: Optional[float] = None
|
||
|
|
oven_capacity_hours: Optional[float] = None
|
||
|
|
production_capacity_limit: Optional[float] = None
|
||
|
|
schedule_notes: Optional[str] = None
|
||
|
|
preparation_instructions: Optional[str] = None
|
||
|
|
special_requirements: Optional[Dict[str, Any]] = None
|
||
|
|
created_at: datetime
|
||
|
|
updated_at: datetime
|
||
|
|
created_by: Optional[UUID] = None
|
||
|
|
published_by: Optional[UUID] = None
|
||
|
|
published_at: Optional[datetime] = None
|
||
|
|
|
||
|
|
class Config:
|
||
|
|
from_attributes = True
|
||
|
|
|
||
|
|
|
||
|
|
class ProductionStatisticsResponse(BaseModel):
|
||
|
|
"""Schema for production statistics responses"""
|
||
|
|
total_batches: int
|
||
|
|
completed_batches: int
|
||
|
|
failed_batches: int
|
||
|
|
success_rate: float
|
||
|
|
average_yield_percentage: float
|
||
|
|
average_quality_score: float
|
||
|
|
total_production_cost: float
|
||
|
|
status_breakdown: List[Dict[str, Any]]
|
||
|
|
|
||
|
|
|
||
|
|
class StartProductionRequest(BaseModel):
|
||
|
|
"""Schema for starting production batch"""
|
||
|
|
staff_member: Optional[UUID] = None
|
||
|
|
production_notes: Optional[str] = None
|
||
|
|
ingredient_consumptions: List[ProductionIngredientConsumptionCreate]
|
||
|
|
|
||
|
|
|
||
|
|
class CompleteProductionRequest(BaseModel):
|
||
|
|
"""Schema for completing production batch"""
|
||
|
|
actual_quantity: float = Field(..., gt=0)
|
||
|
|
quality_score: Optional[float] = Field(None, ge=1, le=10)
|
||
|
|
quality_notes: Optional[str] = None
|
||
|
|
defect_rate: Optional[float] = Field(None, ge=0, le=100)
|
||
|
|
waste_quantity: Optional[float] = Field(None, ge=0)
|
||
|
|
waste_reason: Optional[str] = None
|
||
|
|
production_notes: Optional[str] = None
|
||
|
|
staff_member: Optional[UUID] = None
|