from pydantic import BaseModel, Field from datetime import date, datetime from typing import Optional, List # ============ 财务账户 Schema ============ class AccountBase(BaseModel): """账户基础模型""" name: str = Field(..., min_length=1, max_length=100) account_type: str = Field(default="savings", pattern="^(savings|debt)$") balance: float = Field(default=0.0) icon: str = Field(default="wallet", max_length=50) color: str = Field(default="#FFB7C5", max_length=20) sort_order: int = Field(default=0) is_active: bool = Field(default=True) description: Optional[str] = None class AccountCreate(AccountBase): """创建账户请求模型""" pass class AccountUpdate(BaseModel): """更新账户请求模型""" name: Optional[str] = Field(None, max_length=100) account_type: Optional[str] = Field(None, pattern="^(savings|debt)$") balance: Optional[float] = None icon: Optional[str] = Field(None, max_length=50) color: Optional[str] = Field(None, max_length=20) sort_order: Optional[int] = None is_active: Optional[bool] = None description: Optional[str] = None class AccountResponse(AccountBase): """账户响应模型""" id: int created_at: datetime updated_at: datetime class Config: from_attributes = True class AccountListItemResponse(BaseModel): """账户列表项响应模型(含分期摘要)""" id: int name: str account_type: str balance: float icon: str color: str sort_order: int is_active: bool description: Optional[str] = None created_at: datetime updated_at: datetime installments: List[dict] = [] class BalanceUpdateRequest(BaseModel): """更新余额请求模型""" new_balance: float note: Optional[str] = Field(None, max_length=200) # ============ 账户变更历史 Schema ============ class AccountHistoryResponse(BaseModel): """变更历史响应模型""" id: int account_id: int change_amount: float balance_before: float balance_after: float note: Optional[str] = None created_at: datetime class Config: from_attributes = True # ============ 分期还款计划 Schema ============ class DebtInstallmentBase(BaseModel): """分期计划基础模型""" account_id: int total_amount: float total_periods: int = Field(..., ge=1) current_period: int = Field(default=1, ge=1) payment_day: int = Field(..., ge=1, le=31) payment_amount: float = Field(..., gt=0) start_date: date is_completed: bool = Field(default=False) class DebtInstallmentCreate(DebtInstallmentBase): """创建分期计划请求模型""" pass class DebtInstallmentUpdate(BaseModel): """更新分期计划请求模型""" account_id: Optional[int] = None total_amount: Optional[float] = None total_periods: Optional[int] = Field(None, ge=1) current_period: Optional[int] = Field(None, ge=1) payment_day: Optional[int] = Field(None, ge=1, le=31) payment_amount: Optional[float] = Field(None, gt=0) start_date: Optional[date] = None is_completed: Optional[bool] = None class DebtInstallmentResponse(DebtInstallmentBase): """分期计划响应模型(含计算字段)""" id: int created_at: datetime updated_at: datetime # 计算字段 next_payment_date: Optional[date] = None days_until_payment: Optional[int] = None remaining_periods: Optional[int] = None # 关联账户信息 account_name: Optional[str] = None account_icon: Optional[str] = None account_color: Optional[str] = None class Config: from_attributes = True