from __future__ import annotations import asyncio import json from sqlalchemy import text from app.models.base import async_session from app.services.credit.utils import utc_now _UNRESOLVED_HOLDS_SQL = text( """ SELECT h.id, h.user_id, h.biz_key, h.amount, h.created_at FROM credit_records AS h WHERE h.type = 'hold' AND NOT EXISTS ( SELECT 1 FROM credit_records AS x WHERE x.refund_for_biz_key = h.biz_key OR x.biz_key IN ( REPLACE(h.biz_key, :hold_suffix, :hold_release_suffix), REPLACE(h.biz_key, :hold_suffix, :charge_suffix) ) ) ORDER BY h.created_at ASC LIMIT 5000 """ ) async def amain() -> int: """维护窗口检查脚本:列出旧 HOLD 未形成 RELEASE/CHARGE 的业务,禁止带病切换。""" async with async_session() as db: result = await db.execute( _UNRESOLVED_HOLDS_SQL, { "hold_suffix": ":hold", "hold_release_suffix": ":hold_release", "charge_suffix": ":charge", }, ) rows = result.mappings().all() print( json.dumps( { "checked_at": utc_now().isoformat(), "unresolved_count": len(rows), "items": [dict(row) for row in rows], }, ensure_ascii=False, indent=2, default=str, ) ) return 0 if not rows else 2 if __name__ == "__main__": raise SystemExit(asyncio.run(amain()))