from typing import List, Optional from pydantic import BaseModel, ConfigDict, field_validator from pydantic.alias_generators import to_camel def _coerce_id(value) -> str: if value is None: return "0" return str(value).strip() class ExpenseItemCreate(BaseModel): model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel) parent_id: str = "0" item_name: str item_code: str level: int = 1 sort_order: int = 0 status: int = 1 remark: Optional[str] = None @field_validator("parent_id", mode="before") @classmethod def validate_parent_id(cls, value): return _coerce_id(value) class ExpenseItemUpdate(BaseModel): model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel) parent_id: Optional[str] = None item_name: Optional[str] = None item_code: Optional[str] = None level: Optional[int] = None sort_order: Optional[int] = None status: Optional[int] = None remark: Optional[str] = None @field_validator("parent_id", mode="before") @classmethod def validate_parent_id(cls, value): if value is None: return None return _coerce_id(value) class ExpenseItemOut(BaseModel): model_config = ConfigDict(from_attributes=True, populate_by_name=True, alias_generator=to_camel) id: str parent_id: str item_name: str item_code: Optional[str] = None level: int sort_order: int status: int remark: Optional[str] = None create_by: Optional[str] = None child_count: int = 0 children: Optional[List["ExpenseItemOut"]] = None ExpenseItemOut.model_rebuild()