Files
vps-manager/app/services/renewal_service.py
T

76 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""续费检查服务
检查即将到期的资产,生成提醒消息并通过通知渠道发送。
"""
from datetime import date
from sqlmodel import Session, select
from app.core.config import settings
from app.models.asset import Asset, AssetStatus
from app.services import notification_service
# 已注销的资产不参与续费提醒
_SKIP_STATUS = {AssetStatus.CANCELLED}
def get_expiring_assets(session: Session, threshold_days: int) -> list:
"""返回 threshold_days 天内到期的资产列表 [(asset, days), ...],按剩余天数升序"""
today = date.today()
assets = session.exec(select(Asset).where(Asset.expiry_date.is_not(None))).all()
expiring = []
for asset in assets:
if asset.status in _SKIP_STATUS:
continue
days = (asset.expiry_date - today).days
if 0 <= days <= threshold_days:
expiring.append((asset, days))
expiring.sort(key=lambda x: x[1])
return expiring
def build_renewal_message(expiring: list, threshold_days: int) -> str:
"""生成续费提醒消息(纯文本,兼容 Telegram/邮件)"""
if not expiring:
return ""
lines = [f"⏰ 资产续费提醒({threshold_days} 天内到期,共 {len(expiring)} 项)", ""]
for asset, days in expiring:
tag = "(已过期)" if days == 0 else f"{days} 天后)"
lines.append(f"• {asset.name} [{asset.provider}] {tag} 到期 {asset.expiry_date}")
return "\n".join(lines)
def check_renewals(session: Session, threshold_days: int = None, send: bool = True) -> dict:
"""检查续费并(可选)发送提醒
threshold_days: 提醒阈值天数,默认取配置 RENEWAL_THRESHOLD_DAYS
send: 是否实际发送通知(False 时仅返回预览)
"""
if threshold_days is None:
threshold_days = settings.RENEWAL_THRESHOLD_DAYS
expiring = get_expiring_assets(session, threshold_days)
message = build_renewal_message(expiring, threshold_days)
result = {
"threshold_days": threshold_days,
"expiring_count": len(expiring),
"expiring": [
{
"name": asset.name,
"provider": asset.provider,
"days": days,
"expiry_date": str(asset.expiry_date),
}
for asset, days in expiring
],
"message": message,
}
if send and message:
result["notifications"] = notification_service.notify(message)
else:
result["notifications"] = []
return result