from __future__ import annotations from datetime import UTC, datetime from enum import StrEnum from typing import Annotated, Literal from annotated_types import MinLen from pydantic import BaseModel, Field from pydantic_extra_types.currency_code import Currency from ulid import ULID from .ref import AccountRef class AccountType(StrEnum): """资金性质""" ASSET = "ASSET" LIABILITY = "LIABILITY" EQUITY = "EQUITY" class BaseAccount(BaseModel): """基础账户模型""" id: ULID = Field(default_factory=ULID) name: Annotated[str, "用户自定义名称", MinLen(1)] account_type: AccountType primary_currency: Annotated[Currency | None, "主币种(可选)", Field(default=None)] supported_currencies: Annotated[ list[Currency] | None, "支持的币种列表(None=全币种)", Field(default=None) ] is_active: Annotated[bool, "是否启用", Field(default=True)] remark: Annotated[str | None, "备注", Field(default=None)] created_at: Annotated[datetime, "创建时间", Field(default_factory=lambda: datetime.now(UTC))] updated_at: Annotated[datetime, "更新时间", Field(default_factory=lambda: datetime.now(UTC))] deleted_at: Annotated[datetime | None, "软删除时间(None=未删除)", Field(default=None)] class BankAccount(BaseAccount): """银行账户""" account_type: Literal[AccountType.ASSET, AccountType.LIABILITY] = AccountType.ASSET issuer_name: Annotated[str, "银行名称", MinLen(1)] account_number: Annotated[str | None, "完整账户号(敏感信息)", Field(default=None)] account_suffix: Annotated[ str | None, "账户号末尾部分,用于识别", MinLen(1), Field(default=None) ] sub_accounts: Annotated[list[AccountRef], "子账户引用", Field(default_factory=list)] class EWalletAccount(BaseAccount): """电子钱包账户""" account_type: Literal[AccountType.ASSET] = AccountType.ASSET platform: Annotated[ str, "平台名称: Alipay/WeChat/PayMe/AlipayHK/MPay/Octopus/Tap&Go/AlipayMO", MinLen(1), ] account_id: Annotated[str | None, "平台账户ID", Field(default=None)] class CashAccount(BaseAccount): """现金账户""" account_type: Literal[AccountType.ASSET] = AccountType.ASSET location: Annotated[str | None, "存放位置描述", Field(default=None)] type Account = Annotated[ BankAccount | EWalletAccount | CashAccount, Field(discriminator="account_type"), ]