"""admin 钱包(金币/现金流水 + 提现单)schemas。""" from __future__ import annotations from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from app.admin.schemas.admin import AdminAuditLogOut class CoinTxnOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int user_id: int amount: int balance_after: int biz_type: str ref_id: str | None = None remark: str | None = None created_at: datetime class CashTxnOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int user_id: int amount_cents: int balance_after_cents: int biz_type: str ref_id: str | None = None remark: str | None = None created_at: datetime class WithdrawOrderOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int user_id: int out_bill_no: str amount_cents: int user_name: str | None = None # 提现实名(审核核对 + 打款用) status: str wechat_state: str | None = None transfer_bill_no: str | None = None fail_reason: str | None = None created_at: datetime updated_at: datetime class WithdrawListItemOut(WithdrawOrderOut): """提现单列表项:在提现单字段基础上,补本页用户的手机号/昵称 + 累计成功提现金额(分)。 仅列表接口用(需联表 User + 聚合);详情/批量仍用 WithdrawOrderOut(不带这些字段)。 """ phone: str | None = None nickname: str | None = None cumulative_success_cents: int = 0 # 累计成功提现 = SUM(amount_cents) WHERE status='success' class WithdrawSummaryOut(BaseModel): reviewing_count: int reviewing_amount_cents: int pending_count: int failed_count: int today_success_count: int today_success_amount_cents: int today_rejected_count: int class WithdrawUserSnapshot(BaseModel): id: int phone: str nickname: str | None = None status: str wechat_nickname: str | None = None wechat_avatar_url: str | None = None created_at: datetime last_login_at: datetime cash_balance_cents: int withdraw_total: int withdraw_success_cents: int class WithdrawDetailOut(BaseModel): order: WithdrawOrderOut user: WithdrawUserSnapshot | None = None risk_flags: list[str] risk_score: int recent_withdraws: list[WithdrawOrderOut] recent_cash_transactions: list[CashTxnOut] audit_logs: list[AdminAuditLogOut] class ReconcileResult(BaseModel): checked: int resolved: int class WithdrawBulkRequest(BaseModel): out_bill_nos: list[str] = Field( ..., min_length=1, max_length=50, description="提现商户单号列表" ) class WithdrawBulkRejectRequest(WithdrawBulkRequest): reason: str = Field( ..., min_length=1, max_length=200, description="批量拒绝理由(用户可见)" ) class WithdrawBulkItemResult(BaseModel): out_bill_no: str ok: bool status: str | None = None error: str | None = None class WithdrawBulkResult(BaseModel): total: int success: int failed: int items: list[WithdrawBulkItemResult] class WithdrawLedgerCheckOut(BaseModel): ok: bool cash_balance_total_cents: int cash_transaction_total_cents: int balance_diff_cents: int missing_withdraw_txn_count: int missing_refund_txn_count: int duplicate_refund_txn_count: int refund_txn_on_non_terminal_count: int class WxpayHealthCheckOut(BaseModel): ok: bool wxpay_configured: bool wxpay_auth_configured: bool private_key_path: str private_key_exists: bool private_key_loadable: bool public_key_path: str public_key_exists: bool public_key_loadable: bool auth_notify_url_configured: bool auto_reconcile_enabled: bool auto_reconcile_interval_sec: int auto_reconcile_older_than_minutes: int issues: list[str] class WithdrawRejectRequest(BaseModel): reason: str = Field( ..., min_length=1, max_length=200, description="拒绝理由(写入 fail_reason,用户可见)" )