修复虚拟支付

This commit is contained in:
2026-09-14 01:52:32 +08:00
parent b6e842ac9b
commit d87f904e33
3 changed files with 145 additions and 51 deletions
+17 -15
View File
@@ -167,7 +167,7 @@ func (s *OrderService) XPayNotify(ctx context.Context, raw []byte) []byte {
}
// verifyXPayOrderPaid 反查微信侧订单真实性:消息推送无签名,发货前必须通过
// query_order(带 HMAC 签名的服务端 API)确认订单已真实支付、金额与道具一致,
// query_order(带 HMAC 签名的服务端 API)确认订单已真实支付、实付金额一致,
// 防止伪造发货推送零成本获取权益。任一校验不通过返回错误(fail-closed,触发微信重试)。
func (s *OrderService) verifyXPayOrderPaid(ctx context.Context, order *mysqlmodel.Order, deliver *wechat.XPayGoodsDeliverNotify) *errcode.Error {
if deliver.OpenID == "" {
@@ -183,22 +183,19 @@ func (s *OrderService) verifyXPayOrderPaid(ctx context.Context, order *mysqlmode
}
// 微信侧无支付记录/未支付:伪造推送或数据异常,拒绝发放。
if !wechat.IsOrderPaidStatus(info.Status) {
if !wechat.IsOrderPaidStatus(info.Order.Status) {
slog.ErrorContext(ctx, "xpay deliver: order not paid in wechat side",
"order_no", order.OrderNo, "query_status", info.Status)
"order_no", order.OrderNo, "query_status", info.Order.Status)
return errcode.OrderRealityCheckFailed
}
// 反查金额与道具必须与下单快照一致(资损防线)。
if info.PayFee != order.PayAmount {
// 反查金额必须与下单快照一致(资损防线)。
if info.Order.PaidFee != order.PayAmount {
slog.ErrorContext(ctx, "xpay deliver: query amount mismatch",
"order_no", order.OrderNo, "query_amount", info.PayFee, "order_amount", order.PayAmount)
return errcode.OrderRealityCheckFailed
}
if info.ProductID != order.XPayProductID {
slog.ErrorContext(ctx, "xpay deliver: query product mismatch",
"order_no", order.OrderNo, "query_product", info.ProductID, "order_product", order.XPayProductID)
"order_no", order.OrderNo, "query_amount", info.Order.PaidFee, "order_amount", order.PayAmount)
return errcode.OrderRealityCheckFailed
}
// 道具一致性由推送报文层校验(deliver.GoodsInfo.ProductID 对订单快照);
// query_order 不回传 product_id,无法在此二次核对,故不再重复校验。
return nil
}
@@ -219,15 +216,20 @@ func (s *OrderService) verifyXPayRefund(ctx context.Context, order *mysqlmodel.O
}
// 微信侧无退款记录/未退款:伪造推送或数据异常,拒绝回退权益。
if !wechat.IsOrderRefundedStatus(info.RefundStatus) {
if !wechat.IsOrderRefundedStatus(info.Order.Status) {
slog.ErrorContext(ctx, "xpay refund: order not refunded in wechat side",
"order_no", order.OrderNo, "refund_status", info.RefundStatus)
"order_no", order.OrderNo, "query_status", info.Order.Status)
return errcode.OrderRealityCheckFailed
}
// 反查退款金额必须与推送一致(资损防线)。
if info.RefundFee != refund.RefundFee {
// 退款单用 refund_fee;支付单退款后用 paid_fee - left_fee 推算累计已退金额。
refundedFee := info.Order.RefundFee
if refundedFee <= 0 {
refundedFee = info.Order.PaidFee - info.Order.LeftFee
}
if refundedFee != refund.RefundFee {
slog.ErrorContext(ctx, "xpay refund: refund amount mismatch",
"order_no", order.OrderNo, "query_refund_fee", info.RefundFee, "notify_refund_fee", refund.RefundFee)
"order_no", order.OrderNo, "query_refunded_fee", refundedFee, "notify_refund_fee", refund.RefundFee)
return errcode.OrderRealityCheckFailed
}
return nil