343 lines
8.4 KiB
Python
343 lines
8.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import date
|
|
from datetime import datetime
|
|
from typing import Literal
|
|
from uuid import UUID
|
|
|
|
from pydantic import ConfigDict, EmailStr, Field, field_validator
|
|
|
|
from app.models.customer import CustomerType
|
|
from app.models.equipment import EquipmentKind, EquipmentStatus
|
|
from app.models.report_settings import (
|
|
OrionImagePosition,
|
|
OrionImageSize,
|
|
OrionLayoutProfile,
|
|
OrionLogoSize,
|
|
OrionPageMargin,
|
|
OrionSignatureMode,
|
|
OrionSpacing,
|
|
OrionTableFontSize,
|
|
)
|
|
from app.models.user import UserRole
|
|
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 OrionReportSettingsUpdate(ORMModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
layout_profile: OrionLayoutProfile
|
|
show_cover_result_text: bool
|
|
signature_mode: OrionSignatureMode
|
|
image_size: OrionImageSize
|
|
page_break_before_main_chapters: bool
|
|
page_margin: OrionPageMargin
|
|
section_spacing: OrionSpacing
|
|
table_layout: OrionSpacing
|
|
table_font_size: OrionTableFontSize
|
|
image_position: OrionImagePosition
|
|
max_images_per_page: Literal[1, 2, 4]
|
|
show_image_captions: bool
|
|
show_header: bool
|
|
show_footer: bool
|
|
logo_size: OrionLogoSize
|
|
compact_cover: bool
|
|
|
|
|
|
class OrionReportSettingsRead(OrionReportSettingsUpdate, EntityRead):
|
|
scope: str
|
|
updated_by_user_id: str | None = None
|
|
|
|
|
|
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]
|
|
|
|
|
|
class UserBase(ORMModel):
|
|
first_name: str
|
|
last_name: str
|
|
email: EmailStr
|
|
role: UserRole
|
|
is_active: bool = True
|
|
must_change_password: bool = True
|
|
|
|
|
|
class UserCreate(UserBase):
|
|
temporary_password: str
|
|
|
|
|
|
class UserUpdate(UserBase):
|
|
pass
|
|
|
|
|
|
class UserRead(UserBase, EntityRead):
|
|
last_login_at: datetime | None = None
|
|
password_changed_at: datetime | None = None
|
|
|
|
|
|
class UserPasswordResetRequest(ORMModel):
|
|
temporary_password: str | None = None
|
|
|
|
|
|
class QuickStartValidationSummary(ORMModel):
|
|
id: str
|
|
device_id: str
|
|
report_number: str
|
|
performed_on: date | None = None
|
|
result: str | None = None
|
|
next_validation_on: date | None = None
|
|
status: str
|
|
validation_type: str | None = None
|
|
equipment_ids: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class QuickStartCustomerData(ORMModel):
|
|
customer: CustomerRead
|
|
locations: list[LocationRead] = Field(default_factory=list)
|
|
contacts: list[ContactRead] = Field(default_factory=list)
|
|
devices: list[DeviceRead] = Field(default_factory=list)
|
|
validations: list[QuickStartValidationSummary] = Field(default_factory=list)
|
|
|
|
|
|
class QuickStartCreateRequest(ORMModel):
|
|
customer_id: UUID
|
|
location_id: UUID | None = None
|
|
contact_id: UUID | None = None
|
|
device_id: UUID | None = None
|
|
validation_type: str
|
|
|
|
@field_validator("location_id", "contact_id", "device_id", mode="before")
|
|
@classmethod
|
|
def empty_string_to_none(cls, value):
|
|
if value == "":
|
|
return None
|
|
return value
|