from pydantic import BaseModel, Field from datetime import datetime from typing import Optional, List 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" # 기타 # User schemas class UserBase(BaseModel): username: str full_name: Optional[str] = None role: UserRole = UserRole.user class UserCreate(UserBase): password: str class UserUpdate(BaseModel): full_name: Optional[str] = None password: Optional[str] = None role: Optional[UserRole] = 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 class Config: from_attributes = True # 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