Files
bakery-ia/services/production/app/schemas/quality_templates.py
2025-09-23 19:24:22 +02:00

179 lines
8.3 KiB
Python

# services/production/app/schemas/quality_templates.py
"""
Quality Check Template Pydantic schemas for validation and serialization
"""
from pydantic import BaseModel, Field, validator
from typing import Optional, List, Dict, Any, Union
from uuid import UUID
from datetime import datetime
from enum import Enum
from ..models.production import ProcessStage
class QualityCheckType(str, Enum):
"""Quality check types"""
VISUAL = "visual"
MEASUREMENT = "measurement"
TEMPERATURE = "temperature"
WEIGHT = "weight"
BOOLEAN = "boolean"
TIMING = "timing"
class QualityCheckTemplateBase(BaseModel):
"""Base schema for quality check templates"""
name: str = Field(..., min_length=1, max_length=255, description="Template name")
template_code: Optional[str] = Field(None, max_length=100, description="Template code for reference")
check_type: QualityCheckType = Field(..., description="Type of quality check")
category: Optional[str] = Field(None, max_length=100, description="Check category (e.g., appearance, structure)")
description: Optional[str] = Field(None, description="Template description")
instructions: Optional[str] = Field(None, description="Check instructions for staff")
# Configuration
parameters: Optional[Dict[str, Any]] = Field(None, description="Dynamic check parameters")
thresholds: Optional[Dict[str, Any]] = Field(None, description="Pass/fail criteria")
scoring_criteria: Optional[Dict[str, Any]] = Field(None, description="Scoring methodology")
# Settings
is_active: bool = Field(True, description="Whether template is active")
is_required: bool = Field(False, description="Whether check is required")
is_critical: bool = Field(False, description="Whether failure blocks production")
weight: float = Field(1.0, ge=0.0, le=10.0, description="Weight in overall quality score")
# Measurement specifications
min_value: Optional[float] = Field(None, description="Minimum acceptable value")
max_value: Optional[float] = Field(None, description="Maximum acceptable value")
target_value: Optional[float] = Field(None, description="Target value")
unit: Optional[str] = Field(None, max_length=20, description="Unit of measurement")
tolerance_percentage: Optional[float] = Field(None, ge=0.0, le=100.0, description="Tolerance percentage")
# Process stage applicability
applicable_stages: Optional[List[ProcessStage]] = Field(None, description="Applicable process stages")
@validator('applicable_stages')
def validate_stages(cls, v):
if v is not None:
# Ensure all values are valid ProcessStage enums
for stage in v:
if stage not in ProcessStage:
raise ValueError(f"Invalid process stage: {stage}")
return v
@validator('min_value', 'max_value', 'target_value')
def validate_measurement_values(cls, v, values):
if v is not None and values.get('check_type') not in [QualityCheckType.MEASUREMENT, QualityCheckType.TEMPERATURE, QualityCheckType.WEIGHT]:
return None # Clear values for non-measurement types
return v
class QualityCheckTemplateCreate(QualityCheckTemplateBase):
"""Schema for creating quality check templates"""
created_by: UUID = Field(..., description="User ID who created the template")
class QualityCheckTemplateUpdate(BaseModel):
"""Schema for updating quality check templates"""
name: Optional[str] = Field(None, min_length=1, max_length=255)
template_code: Optional[str] = Field(None, max_length=100)
check_type: Optional[QualityCheckType] = None
category: Optional[str] = Field(None, max_length=100)
description: Optional[str] = None
instructions: Optional[str] = None
parameters: Optional[Dict[str, Any]] = None
thresholds: Optional[Dict[str, Any]] = None
scoring_criteria: Optional[Dict[str, Any]] = None
is_active: Optional[bool] = None
is_required: Optional[bool] = None
is_critical: Optional[bool] = None
weight: Optional[float] = Field(None, ge=0.0, le=10.0)
min_value: Optional[float] = None
max_value: Optional[float] = None
target_value: Optional[float] = None
unit: Optional[str] = Field(None, max_length=20)
tolerance_percentage: Optional[float] = Field(None, ge=0.0, le=100.0)
applicable_stages: Optional[List[ProcessStage]] = None
class QualityCheckTemplateResponse(QualityCheckTemplateBase):
"""Schema for quality check template responses"""
id: UUID
tenant_id: UUID
created_by: UUID
created_at: datetime
updated_at: datetime
class Config:
from_attributes = True
class QualityCheckTemplateList(BaseModel):
"""Schema for paginated quality check template lists"""
templates: List[QualityCheckTemplateResponse]
total: int
skip: int
limit: int
class QualityCheckCriterion(BaseModel):
"""Individual quality check criterion within a template"""
id: str = Field(..., description="Unique criterion identifier")
name: str = Field(..., description="Criterion name")
description: str = Field(..., description="Criterion description")
check_type: QualityCheckType = Field(..., description="Type of check")
required: bool = Field(True, description="Whether criterion is required")
weight: float = Field(1.0, ge=0.0, le=10.0, description="Weight in template score")
acceptable_criteria: str = Field(..., description="Description of acceptable criteria")
min_value: Optional[float] = None
max_value: Optional[float] = None
unit: Optional[str] = None
is_critical: bool = Field(False, description="Whether failure is critical")
class QualityCheckResult(BaseModel):
"""Result of a quality check criterion"""
criterion_id: str = Field(..., description="Criterion identifier")
value: Union[float, str, bool] = Field(..., description="Check result value")
score: float = Field(..., ge=0.0, le=10.0, description="Score for this criterion")
notes: Optional[str] = Field(None, description="Additional notes")
photos: Optional[List[str]] = Field(None, description="Photo URLs")
pass_check: bool = Field(..., description="Whether criterion passed")
timestamp: datetime = Field(..., description="When check was performed")
class QualityCheckExecutionRequest(BaseModel):
"""Schema for executing a quality check using a template"""
template_id: UUID = Field(..., description="Quality check template ID")
batch_id: UUID = Field(..., description="Production batch ID")
process_stage: ProcessStage = Field(..., description="Current process stage")
checker_id: Optional[str] = Field(None, description="Staff member performing check")
results: List[QualityCheckResult] = Field(..., description="Check results")
final_notes: Optional[str] = Field(None, description="Final notes")
photos: Optional[List[str]] = Field(None, description="Additional photo URLs")
class QualityCheckExecutionResponse(BaseModel):
"""Schema for quality check execution results"""
check_id: UUID = Field(..., description="Created quality check ID")
overall_score: float = Field(..., ge=0.0, le=10.0, description="Overall quality score")
overall_pass: bool = Field(..., description="Whether check passed overall")
critical_failures: List[str] = Field(..., description="List of critical failures")
corrective_actions: List[str] = Field(..., description="Recommended corrective actions")
timestamp: datetime = Field(..., description="When check was completed")
class ProcessStageQualityConfig(BaseModel):
"""Configuration for quality checks at a specific process stage"""
stage: ProcessStage = Field(..., description="Process stage")
template_ids: List[UUID] = Field(..., description="Required template IDs")
custom_parameters: Optional[Dict[str, Any]] = Field(None, description="Stage-specific parameters")
is_required: bool = Field(True, description="Whether stage requires quality checks")
blocking: bool = Field(True, description="Whether stage blocks on failed checks")
class RecipeQualityConfiguration(BaseModel):
"""Quality check configuration for a recipe"""
stages: Dict[str, ProcessStageQualityConfig] = Field(..., description="Stage configurations")
global_parameters: Optional[Dict[str, Any]] = Field(None, description="Global quality parameters")
default_templates: Optional[List[UUID]] = Field(None, description="Default template IDs")