fix: 修复付费机制失效处理的5个后端缺口

- 新增POST /payment/refund-notify支付宝退款Webhook
- 新增待支付订单自动清理(超过24h→cancelled, 含启动清理)
- 新增web登录码过期启动清理
- 永久会员用NULL替代硬编码2099-12-31
- 修复缺失的is_paid_active数据库函数(改用内联SQL)
This commit is contained in:
2026-05-25 12:07:01 +08:00
parent f9f1ffeff6
commit af2837e15e
5 changed files with 213 additions and 16 deletions

View File

@@ -844,6 +844,61 @@ pub async fn payment_success(
.body(html)
}
// ===== Handler: POST /payment/refund-notify — 支付宝退款异步回调 =====
#[post("/payment/refund-notify")]
pub async fn alipay_refund_notify(
pool: web::Data<PgPool>,
body: web::Form<BTreeMap<String, String>>,
) -> HttpResponse {
let body = body.into_inner();
let out_trade_no = body.get("out_trade_no").cloned().unwrap_or_default();
let refund_status = body.get("refund_status").cloned().unwrap_or_default();
tracing::info!(
"收到支付宝退款回调: out_trade_no={}, refund_status={}",
out_trade_no,
refund_status
);
// 只处理成功的退款
if refund_status != "REFUND_SUCCESS" {
return HttpResponse::Ok().body("success");
}
// 验证 RSA2 签名
let Some(config) = AlipayConfig::from_env() else {
tracing::warn!("支付宝配置不存在,无法验证退款签名");
return HttpResponse::Ok().body("fail");
};
let sign = body.get("sign").cloned().unwrap_or_default();
let sign_source: String = body
.iter()
.filter(|(k, _)| *k != "sign" && *k != "sign_type")
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<_>>()
.join("&");
if let Err(e) = rsa2_verify(&sign_source, &sign, &config.alipay_public_key) {
tracing::warn!("支付宝退款签名验证失败: {}", e);
return HttpResponse::Ok().body("fail");
}
// 处理退款:标记订单 + 撤销会员
match db::refund_payment_order(pool.get_ref(), &out_trade_no).await {
Ok(_) => {
tracing::info!("订单 {} 退款处理成功", out_trade_no);
HttpResponse::Ok().body("success")
}
Err(e) => {
tracing::error!("订单 {} 退款处理失败: {}", out_trade_no, e);
HttpResponse::Ok().body("fail")
}
}
}
// ===== 旧的 API Handler保持兼容=====
/// POST /api/payment/create-order