"""定时检查续费并发送提醒(供 systemd timer 调用) 用法: python scripts/check_renewals.py [threshold_days] [--dry-run] [--no-verify] 默认发送通知;--dry-run 只打印、不发送,便于核对平台真实状态。 依赖 .env 中的通知渠道配置与账号登录凭据(TELEGRAM_*/SMTP_*、credentials)。 """ import argparse import sys from pathlib import Path # 确保能导入 app 包(脚本位于 scripts/ 子目录) sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from sqlmodel import Session from app.database import assets_engine, init_db from app.services import renewal_service def main() -> int: parser = argparse.ArgumentParser(description="检查资产续费并发送提醒") parser.add_argument("threshold_days", nargs="?", type=int, default=None) parser.add_argument("--dry-run", action="store_true", help="只打印,不发送通知") parser.add_argument("--no-verify", action="store_true", help="跳过平台真实状态核对") args = parser.parse_args() init_db() with Session(assets_engine) as session: result = renewal_service.check_renewals( session, threshold_days=args.threshold_days, send=not args.dry_run, verify=not args.no_verify, ) # days 可为负(已过期),汇总行拆开统计,单项文案复用 day_text(与提醒消息一致) overdue = sum(1 for item in result["expiring"] if item["days"] < 0) summary = ( f"[续费检查] 阈值 {result['threshold_days']} 天 | 已过期 {overdue} 项 | " f"即将到期 {result['expiring_count'] - overdue} 项" ) verification = result.get("verification") if verification: summary += ( f" | 已核对 {verification['verified']} 项" f" | 未核对 {verification['unverified']} 项" ) print(summary) for item in result["expiring"]: print( f" - {item['name']} [{item['provider']}] " f"{renewal_service.day_text(item['days'])}(到期 {item['expiry_date']})" ) if item.get("verified") is True: print(f" 已核对[{item['verify_source']}]: {item['verify_detail']}") elif item.get("verified") is False: print(f" 未核对: {item['verify_detail']}") for n in result.get("notifications", []): status = "成功" if n["ok"] else f"失败:{n['message']}" print(f" 通知[{n['channel']}]: {status}") return 0 if __name__ == "__main__": sys.exit(main())