""" 租戶相關 Pydantic Schemas """ from datetime import datetime from typing import Optional, List from pydantic import BaseModel, Field, validator class TenantBase(BaseModel): """租戶基本資料""" code: str = Field(..., min_length=2, max_length=50, description="租戶代碼") name: str = Field(..., min_length=1, max_length=200, description="公司名稱") name_eng: Optional[str] = Field(None, max_length=200, description="公司英文名稱") tax_id: Optional[str] = Field(None, max_length=20, description="統一編號") prefix: str = Field(..., min_length=1, max_length=10, description="員工編號前綴") tel: Optional[str] = Field(None, max_length=50, description="公司電話") add: Optional[str] = Field(None, max_length=500, description="公司地址") url: Optional[str] = Field(None, max_length=200, description="公司網站") plan_id: str = Field(default="starter", description="方案 ID") max_users: int = Field(default=5, ge=1, description="最大用戶數") storage_quota_gb: int = Field(default=100, ge=1, description="總儲存配額 (GB)") class TenantCreateRequest(TenantBase): """建立租戶請求 (Superuser only)""" admin_username: str = Field(..., description="Tenant Admin 帳號") admin_email: str = Field(..., description="Tenant Admin 郵件") admin_name: str = Field(..., description="Tenant Admin 姓名") admin_temp_password: str = Field(..., min_length=8, description="Tenant Admin 臨時密碼") @validator('admin_email') def validate_email(cls, v): """驗證郵件格式""" if '@' not in v: raise ValueError('Invalid email format') return v @validator('tax_id') def validate_tax_id(cls, v): """驗證統一編號 (台灣 8 位數字)""" if v and (not v.isdigit() or len(v) != 8): raise ValueError('Tax ID must be 8 digits') return v class TenantCreateResponse(BaseModel): """建立租戶回應""" message: str tenant: dict admin_user: dict keycloak_realm: str temporary_password: str # 返回臨時密碼供管理員記錄 class Config: from_attributes = True class TenantUpdateRequest(BaseModel): """更新租戶請求""" name: Optional[str] = Field(None, min_length=1, max_length=200) name_eng: Optional[str] = Field(None, max_length=200) tax_id: Optional[str] = Field(None, max_length=20) tel: Optional[str] = Field(None, max_length=50) add: Optional[str] = Field(None, max_length=500) url: Optional[str] = Field(None, max_length=200) @validator('tax_id') def validate_tax_id(cls, v): """驗證統一編號""" if v and (not v.isdigit() or len(v) != 8): raise ValueError('Tax ID must be 8 digits') return v class TenantUpdateResponse(BaseModel): """更新租戶回應""" message: str tenant: dict class Config: from_attributes = True class TenantResponse(BaseModel): """租戶詳細資訊""" id: int code: str name: str name_eng: Optional[str] tax_id: Optional[str] prefix: str tel: Optional[str] add: Optional[str] url: Optional[str] keycloak_realm: Optional[str] plan_id: str max_users: int storage_quota_gb: int status: str is_sysmana: bool is_active: bool is_initialized: bool initialized_at: Optional[datetime] initialized_by: Optional[str] created_at: datetime updated_at: datetime class Config: from_attributes = True class InitializationRequest(BaseModel): """租戶初始化請求 (Tenant Admin only)""" # Step 1: 公司基本資料 (可修改) company_info: dict = Field(..., description="公司基本資料") # Step 2: 部門結構 departments: List[dict] = Field(..., description="部門列表") # Step 3: 系統角色 roles: List[dict] = Field(..., description="角色列表") # Step 4: 預設配額與服務 default_settings: dict = Field(..., description="預設配額與服務") class InitializationResponse(BaseModel): """初始化完成回應""" message: str summary: dict class Config: from_attributes = True