import uuid from datetime import datetime from typing import Literal from pydantic import BaseModel, Field, field_validator LedgerRole = Literal["VIEWER", "EDITOR", "MANAGER"] class LedgerRead(BaseModel): id: uuid.UUID title: str description: str status: Literal["ACTIVE", "ARCHIVED"] owner_id: uuid.UUID owner_name: str generation: int updated_at: datetime current_revision_id: uuid.UUID | None current_revision_no: int | None current_revision_file_size: int | None current_revision_mime_type: str | None current_revision_created_at: datetime | None role: LedgerRole can_edit: bool can_manage: bool can_export: bool allow_export: bool allow_edit_request: bool allow_sheet_structure_edit: bool file_type: Literal["cell"] = "cell" extension: Literal["xlsx"] = "xlsx" can_request_edit: bool edit_request_status: Literal["PENDING", "APPROVED", "REJECTED"] | None = None can_transfer_ownership: bool class LedgerSettings(BaseModel): title: str = Field(min_length=1, max_length=240) description: str = Field(default="", max_length=500) status: Literal["ACTIVE", "ARCHIVED"] owner_id: uuid.UUID allow_export: bool = False allow_edit_request: bool | None = None allow_sheet_structure_edit: bool = False generation: int = Field(ge=1) @field_validator("title") @classmethod def trim_title(cls, value): value = value.strip() if not value: raise ValueError("台账名称不能为空") return value class LedgerMemberUpsert(BaseModel): user_id: uuid.UUID role: LedgerRole class LedgerMemberRead(BaseModel): user_id: uuid.UUID full_name: str email: str role: LedgerRole is_active: bool protected_label: str | None = None class LedgerCandidateRead(BaseModel): user_id: uuid.UUID full_name: str email: str role_in_study: str can_be_editor: bool = True can_be_manager: bool = True class LedgerAccessSettings(BaseModel): generation: int = Field(ge=1) allow_export: bool | None = None allow_edit_request: bool | None = None allow_sheet_structure_edit: bool | None = None class LedgerRestore(BaseModel): generation: int = Field(ge=1)