154 lines
4.9 KiB
Python
154 lines
4.9 KiB
Python
"""应用宝充值任务服务。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ..models import YybRechargeTask
|
|
from .yyb_worker_client import YybWorkerClient
|
|
|
|
|
|
def _utcnow():
|
|
return datetime.now(UTC)
|
|
|
|
|
|
def _from_ts(value) -> datetime | None:
|
|
try:
|
|
return datetime.fromtimestamp(int(value), tz=UTC) if value else None
|
|
except (TypeError, ValueError, OSError):
|
|
return None
|
|
|
|
|
|
def _as_utc(value: datetime | None) -> datetime | None:
|
|
"""DB 时间列为 naive UTC;输出时补 UTC 时区标记,前端才能按本地时区正确显示。"""
|
|
if value is None:
|
|
return None
|
|
if value.tzinfo is None:
|
|
return value.replace(tzinfo=UTC)
|
|
return value.astimezone(UTC)
|
|
|
|
|
|
def cleanup_orphan_yyb_tasks(db: Session, message: str) -> int:
|
|
rows = (
|
|
db.query(YybRechargeTask)
|
|
.filter(
|
|
YybRechargeTask.status.in_(
|
|
[
|
|
"created",
|
|
"waiting_login",
|
|
"ready",
|
|
"running",
|
|
"ordering",
|
|
"waiting_payment",
|
|
]
|
|
)
|
|
)
|
|
.all()
|
|
)
|
|
for task in rows:
|
|
if task.status == "ordering":
|
|
task.status = "waiting_payment"
|
|
task.message = "服务重启,支付流程中断,可重新检测到账"
|
|
elif task.status == "waiting_payment":
|
|
task.message = "服务重启,到账检测中断,可重新检测到账"
|
|
else:
|
|
task.status = "failed"
|
|
task.message = message
|
|
task.finished_at = _utcnow()
|
|
if rows:
|
|
db.commit()
|
|
return len(rows)
|
|
|
|
|
|
def sync_task(
|
|
db: Session, task: YybRechargeTask, worker: YybWorkerClient
|
|
) -> YybRechargeTask:
|
|
data = worker.get_job(task.worker_job_id)
|
|
task.status = str(data.get("status", task.status))
|
|
task.phase = str(data.get("phase", task.phase))
|
|
task.message = str(data.get("message", task.message))
|
|
if data.get("provider"):
|
|
task.provider = str(data["provider"])
|
|
if data.get("qr_data"):
|
|
task.login_qr_data = str(data["qr_data"])
|
|
task.result = {
|
|
**(task.result or {}),
|
|
"login_qr_mime_type": data.get("qr_mime_type", "image/jpeg"),
|
|
}
|
|
if data.get("payment_qr_data"):
|
|
task.payment_qr_data = str(data["payment_qr_data"])
|
|
task.result = {
|
|
**(task.result or {}),
|
|
"payment_qr_mime_type": data.get("payment_qr_mime_type", "image/png"),
|
|
}
|
|
task.result = {
|
|
**(task.result or {}),
|
|
"logs": data.get("logs", []),
|
|
"payment_status": data.get("payment_status"),
|
|
}
|
|
qr_created_at = _from_ts(data.get("payment_qr_created_at"))
|
|
if qr_created_at:
|
|
task.payment_qr_created_at = qr_created_at
|
|
last_checked_at = _from_ts(data.get("payment_last_checked_at"))
|
|
if last_checked_at:
|
|
task.payment_last_checked_at = last_checked_at
|
|
if task.status in {"success", "failed"} and task.finished_at is None:
|
|
task.finished_at = _utcnow()
|
|
if (
|
|
task.status not in {"success", "failed", "stopped"}
|
|
and task.finished_at is not None
|
|
):
|
|
task.finished_at = None
|
|
db.commit()
|
|
db.refresh(task)
|
|
return task
|
|
|
|
|
|
def public_task(
|
|
task: YybRechargeTask,
|
|
include_qr: bool = True,
|
|
include_payment_qr: bool | None = None,
|
|
creator_username: str = "",
|
|
) -> dict[str, Any]:
|
|
result: dict[str, Any] = {
|
|
"id": task.id,
|
|
"task_id": task.task_id,
|
|
"provider": task.provider,
|
|
"platform": task.platform,
|
|
"points": task.points,
|
|
"price_fen": task.price_fen,
|
|
"product_id": task.product_id,
|
|
"zone_id": task.zone_id,
|
|
"zone_name": task.zone_name,
|
|
"role_id": task.role_id,
|
|
"role_name": task.role_name,
|
|
"status": task.status,
|
|
"phase": task.phase,
|
|
"message": task.message,
|
|
"result": task.result,
|
|
"created_by": task.created_by,
|
|
"created_by_username": creator_username,
|
|
"created_at": _as_utc(task.created_at),
|
|
"finished_at": _as_utc(task.finished_at),
|
|
"payment_started_at": _as_utc(task.payment_started_at),
|
|
"payment_qr_created_at": _as_utc(task.payment_qr_created_at),
|
|
"payment_last_checked_at": _as_utc(task.payment_last_checked_at),
|
|
}
|
|
if task.result:
|
|
result["login_qr_mime_type"] = task.result.get(
|
|
"login_qr_mime_type", "image/jpeg"
|
|
)
|
|
result["payment_qr_mime_type"] = task.result.get(
|
|
"payment_qr_mime_type", "image/png"
|
|
)
|
|
if include_payment_qr is None:
|
|
include_payment_qr = include_qr
|
|
if include_qr:
|
|
result["login_qr_data"] = task.login_qr_data or ""
|
|
if include_payment_qr:
|
|
result["payment_qr_data"] = task.payment_qr_data or ""
|
|
return result
|