from pydantic import BaseModel, Field from datetime import datetime from typing import Optional, List, Dict, Any from enum import Enum class UserRole(str, Enum): admin = "admin" user = "user" class IssueStatus(str, Enum): new = "new" progress = "progress" complete = "complete" class IssueCategory(str, Enum): material_missing = "material_missing" design_error = "design_error" # 설계미스 (기존 dimension_defect 대체) incoming_defect = "incoming_defect" inspection_miss = "inspection_miss" # 검사미스 (신규 추가) etc = "etc" # 기타 class ReviewStatus(str, Enum): pending_review = "pending_review" # 수신함 (검토 대기) in_progress = "in_progress" # 관리함 (진행 중) completed = "completed" # 관리함 (완료됨) disposed = "disposed" # 폐기함 (폐기됨) class DisposalReasonType(str, Enum): duplicate = "duplicate" # 중복 (기본값) invalid_report = "invalid_report" # 잘못된 신고 not_applicable = "not_applicable" # 해당 없음 spam = "spam" # 스팸/오류 custom = "custom" # 직접 입력 class DepartmentType(str, Enum): production = "production" # 생산 quality = "quality" # 품질 purchasing = "purchasing" # 구매 design = "design" # 설계 sales = "sales" # 영업 # User schemas class UserBase(BaseModel): username: str full_name: Optional[str] = None role: UserRole = UserRole.user department: Optional[DepartmentType] = None class UserCreate(UserBase): password: str class UserUpdate(BaseModel): full_name: Optional[str] = None password: Optional[str] = None role: Optional[UserRole] = None department: Optional[DepartmentType] = None is_active: Optional[bool] = None class PasswordChange(BaseModel): current_password: str new_password: str class User(UserBase): id: int is_active: bool created_at: datetime class Config: from_attributes = True # Auth schemas class Token(BaseModel): access_token: str token_type: str user: User class TokenData(BaseModel): username: Optional[str] = None class LoginRequest(BaseModel): username: str password: str # Issue schemas class IssueBase(BaseModel): category: IssueCategory description: str project_id: int class IssueCreate(IssueBase): photo: Optional[str] = None # Base64 encoded image photo2: Optional[str] = None # Second Base64 encoded image class IssueUpdate(BaseModel): category: Optional[IssueCategory] = None description: Optional[str] = None project_id: Optional[int] = None work_hours: Optional[float] = None detail_notes: Optional[str] = None status: Optional[IssueStatus] = None photo: Optional[str] = None # Base64 encoded image for update photo2: Optional[str] = None # Second Base64 encoded image for update class Issue(IssueBase): id: int photo_path: Optional[str] = None photo_path2: Optional[str] = None # 두 번째 사진 경로 status: IssueStatus reporter_id: int reporter: User project_id: Optional[int] = None # project: Optional['Project'] = None # 순환 참조 방지를 위해 제거 report_date: datetime work_hours: float detail_notes: Optional[str] = None # 수신함 워크플로우 관련 필드들 review_status: ReviewStatus disposal_reason: Optional[DisposalReasonType] = None custom_disposal_reason: Optional[str] = None disposed_at: Optional[datetime] = None reviewed_by_id: Optional[int] = None reviewed_at: Optional[datetime] = None original_data: Optional[Dict[str, Any]] = None modification_log: Optional[List[Dict[str, Any]]] = None # 중복 신고 추적 시스템 duplicate_of_issue_id: Optional[int] = None duplicate_reporters: Optional[List[Dict[str, Any]]] = None # 관리함에서 사용할 추가 필드들 completion_photo_path: Optional[str] = None # 완료 사진 경로 solution: Optional[str] = None # 해결방안 responsible_department: Optional[DepartmentType] = None # 담당부서 responsible_person: Optional[str] = None # 담당자 expected_completion_date: Optional[datetime] = None # 조치 예상일 actual_completion_date: Optional[datetime] = None # 완료 확인일 cause_department: Optional[DepartmentType] = None # 원인부서 management_comment: Optional[str] = None # ISSUE에 대한 의견 project_sequence_no: Optional[int] = None # 프로젝트별 순번 final_description: Optional[str] = None # 최종 내용 final_category: Optional[IssueCategory] = None # 최종 카테고리 # 추가 정보 필드들 (관리함에서 기록용) responsible_person_detail: Optional[str] = None # 해당자 상세 정보 cause_detail: Optional[str] = None # 원인 상세 정보 additional_info_updated_at: Optional[datetime] = None # 추가 정보 입력 시간 additional_info_updated_by_id: Optional[int] = None # 추가 정보 입력자 # 완료 신청 관련 필드들 completion_requested_at: Optional[datetime] = None # 완료 신청 시간 completion_requested_by_id: Optional[int] = None # 완료 신청자 completion_photo_path: Optional[str] = None # 완료 사진 경로 completion_comment: Optional[str] = None # 완료 코멘트 class Config: from_attributes = True # 수신함 워크플로우 전용 스키마들 class IssueDisposalRequest(BaseModel): """부적합 폐기 요청""" disposal_reason: DisposalReasonType = DisposalReasonType.duplicate custom_disposal_reason: Optional[str] = None duplicate_of_issue_id: Optional[int] = None # 중복 대상 이슈 ID class IssueReviewRequest(BaseModel): """부적합 검토 및 수정 요청""" project_id: Optional[int] = None category: Optional[IssueCategory] = None description: Optional[str] = None modifications: Optional[Dict[str, Any]] = None class IssueStatusUpdateRequest(BaseModel): """부적합 상태 변경 요청""" review_status: ReviewStatus completion_photo: Optional[str] = None # 완료 사진 (Base64) solution: Optional[str] = None # 해결방안 responsible_department: Optional[DepartmentType] = None # 담당부서 responsible_person: Optional[str] = None # 담당자 class ManagementUpdateRequest(BaseModel): """관리함에서 사용할 필드 업데이트 요청""" solution: Optional[str] = None # 해결방안 responsible_department: Optional[DepartmentType] = None # 담당부서 responsible_person: Optional[str] = None # 담당자 expected_completion_date: Optional[datetime] = None # 조치 예상일 cause_department: Optional[DepartmentType] = None # 원인부서 management_comment: Optional[str] = None # ISSUE에 대한 의견 completion_photo: Optional[str] = None # 완료 사진 (Base64) final_description: Optional[str] = None # 최종 내용 (부적합명 + 상세 내용) class AdditionalInfoUpdateRequest(BaseModel): """추가 정보 업데이트 요청 (관리함 진행중에서 사용)""" cause_department: Optional[DepartmentType] = None # 원인부서 responsible_person_detail: Optional[str] = None # 해당자 상세 정보 cause_detail: Optional[str] = None # 원인 상세 정보 class CompletionRequestRequest(BaseModel): """완료 신청 요청""" completion_photo: str # 완료 사진 (Base64) completion_comment: Optional[str] = None # 완료 코멘트 class ManagementUpdateRequest(BaseModel): """관리함에서 이슈 업데이트 요청""" final_description: Optional[str] = None final_category: Optional[IssueCategory] = None solution: Optional[str] = None responsible_department: Optional[DepartmentType] = None responsible_person: Optional[str] = None expected_completion_date: Optional[str] = None cause_department: Optional[DepartmentType] = None management_comment: Optional[str] = None completion_comment: Optional[str] = None completion_photo: Optional[str] = None # Base64 review_status: Optional[ReviewStatus] = None class InboxIssue(BaseModel): """수신함용 부적합 정보 (간소화된 버전)""" id: int category: IssueCategory description: str photo_path: Optional[str] = None photo_path2: Optional[str] = None project_id: Optional[int] = None reporter_id: int reporter: User report_date: datetime review_status: ReviewStatus class Config: from_attributes = True class ModificationLogEntry(BaseModel): """수정 이력 항목""" field: str old_value: Any new_value: Any modified_at: datetime modified_by: int # Project schemas class ProjectBase(BaseModel): job_no: str = Field(..., min_length=1, max_length=50) project_name: str = Field(..., min_length=1, max_length=200) class ProjectCreate(ProjectBase): pass class ProjectUpdate(BaseModel): project_name: Optional[str] = Field(None, min_length=1, max_length=200) is_active: Optional[bool] = None class Project(ProjectBase): id: int created_by_id: int created_by: User created_at: datetime is_active: bool # issues: Optional[List['Issue']] = None # 순환 참조 방지를 위해 제거 class Config: from_attributes = True # Daily Work schemas class DailyWorkBase(BaseModel): date: datetime worker_count: int = Field(gt=0) overtime_workers: Optional[int] = 0 overtime_hours: Optional[float] = 0 class DailyWorkCreate(DailyWorkBase): pass class DailyWorkUpdate(BaseModel): worker_count: Optional[int] = Field(None, gt=0) overtime_workers: Optional[int] = None overtime_hours: Optional[float] = None class DailyWork(DailyWorkBase): id: int regular_hours: float overtime_total: float total_hours: float created_by_id: int created_by: User created_at: datetime class Config: from_attributes = True # Report schemas class ReportRequest(BaseModel): start_date: datetime end_date: datetime class CategoryStats(BaseModel): material_missing: int = 0 dimension_defect: int = 0 incoming_defect: int = 0 class ReportSummary(BaseModel): start_date: datetime end_date: datetime total_hours: float total_issues: int category_stats: CategoryStats completed_issues: int average_resolution_time: float # Project Daily Work schemas class ProjectDailyWorkBase(BaseModel): date: datetime project_id: int hours: float class ProjectDailyWorkCreate(ProjectDailyWorkBase): pass class ProjectDailyWork(ProjectDailyWorkBase): id: int created_by_id: int created_at: datetime project: Project class Config: from_attributes = True