from __future__ import annotations from datetime import date from uuid import UUID from pydantic import EmailStr, Field, field_validator from app.models.customer import CustomerType from app.models.equipment import EquipmentKind, EquipmentStatus from app.models.validation import ValidationStatus from app.schemas.common import EntityRead, ORMModel class CustomerCreate(ORMModel): customer_type: CustomerType name: str street: str | None = None postal_code: str | None = None city: str | None = None phone: str | None = None email: EmailStr | None = None hygiene_officer: str | None = None quality_manager: str | None = None notes: str | None = None class CustomerRead(CustomerCreate, EntityRead): pass class CustomerUpdate(CustomerCreate): pass class LocationCreate(ORMModel): customer_id: str name: str street: str | None = None postal_code: str | None = None city: str | None = None room: str | None = None class LocationRead(LocationCreate, EntityRead): pass class LocationUpdate(LocationCreate): pass class ContactCreate(ORMModel): customer_id: str full_name: str function: str | None = None email: EmailStr | None = None phone: str | None = None class ContactRead(ContactCreate, EntityRead): pass class ContactUpdate(ContactCreate): pass class DeviceCreate(ORMModel): customer_id: str location_id: str | None = None manufacturer: str model: str device_type: str | None = None serial_number: str year_built: int | None = None commissioned_on: date | None = None chamber_volume_liters: int | None = None steam_generation: str | None = None water_treatment: str | None = None documentation: str | None = None supplier: str | None = None class DeviceRead(DeviceCreate, EntityRead): pass class DeviceUpdate(DeviceCreate): pass class EquipmentCreate(ORMModel): kind: EquipmentKind manufacturer: str | None = None model: str | None = None serial_number: str calibrated_on: date | None = None calibration_due_on: date | None = None certificate_document_id: str | None = None status: EquipmentStatus = EquipmentStatus.green class EquipmentRead(EquipmentCreate, EntityRead): pass class EquipmentUpdate(EquipmentCreate): pass class ValidationCreate(ORMModel): report_number: str | None = None customer_id: UUID | None = None location_id: UUID | None = None contact_id: UUID | None = None device_id: UUID | None = None validation_type: str | None = None project: str | None = None test_location: str | None = None examiner_name: str | None = None participants: str | None = None operator_name: str | None = None scheduled_on: date | None = None performed_on: date | None = None next_validation_on: date | None = None revalidation_interval_months: int = 24 next_validation_manually_overridden: bool = False version: int = 1 previous_validation_id: UUID | None = None examiner_id: UUID | None = None status: ValidationStatus | str = ValidationStatus.draft result: str | None = None notes: str | None = None equipment_ids: list[str] = Field(default_factory=list) environment_conditions: dict = Field(default_factory=dict) documentation_checklist: list[dict] = Field(default_factory=list) performance_checklist: list[dict] = Field(default_factory=list) programs: list[dict] = Field(default_factory=list) loading_patterns: list[dict] = Field(default_factory=list) measurement_data: list[dict] = Field(default_factory=list) drying: dict = Field(default_factory=dict) recommendations: list[dict] = Field(default_factory=list) attachments: list[dict] = Field(default_factory=list) @field_validator( "customer_id", "location_id", "contact_id", "device_id", "examiner_id", "previous_validation_id", mode="before", ) @classmethod def empty_string_to_none(cls, value): if value == "": return None return value class ValidationRead(ValidationCreate, EntityRead): pass class ValidationUpdate(ValidationCreate): pass class ValidationIssue(ORMModel): field: str message: str section: str class ValidationReview(ORMModel): status: str errors: list[ValidationIssue] warnings: list[ValidationIssue] complete_sections: list[str] class ValidationImportPreviewRow(ORMModel): row_number: int data: dict errors: list[str] duplicate: bool resolved_customer_id: str | None = None resolved_location_id: str | None = None resolved_device_id: str | None = None class ValidationImportPreview(ORMModel): rows: list[ValidationImportPreviewRow] valid_rows: int invalid_rows: int duplicates: int class ValidationImportRequest(ORMModel): rows: list[dict] duplicate_strategy: str = "skip" class ValidationImportSummary(ORMModel): successful: int skipped: int failed: int errors: list[str] = Field(default_factory=list) class MeasurementImportValueRead(ORMModel): id: str test_run: str field_name: str raw_value: str | None = None normalized_value: str | None = None unit: str | None = None source_page: int | None = None source_text: str | None = None confidence: int confirmed: bool corrected_value: str | None = None class MeasurementImportPreviewRead(ORMModel): id: str validation_id: str import_type: str original_filename: str sha256: str parser_version: str status: str values: list[MeasurementImportValueRead] class MeasurementImportValueConfirm(ORMModel): id: str confirmed: bool = False corrected_value: str | None = None class MeasurementImportConfirmRequest(ORMModel): values: list[MeasurementImportValueConfirm]