Files
jnc-server/app/main/api/internal/logic/pay/yunyinsignpaycallbacklogic.go
2026-01-16 18:23:43 +08:00

192 lines
6.3 KiB
Go
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.

package pay
import (
"context"
"jnc-server/app/main/api/internal/svc"
"jnc-server/pkg/lzkit/lzUtils"
"net/http"
"strconv"
"time"
"github.com/zeromicro/go-zero/core/logx"
)
type YunYinSignPayCallbackLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewYunYinSignPayCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *YunYinSignPayCallbackLogic {
return &YunYinSignPayCallbackLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// YunYinSignPayCallback 云印签支付回调处理
func (l *YunYinSignPayCallbackLogic) YunYinSignPayCallback(w http.ResponseWriter, r *http.Request) error {
// 检查云印签支付服务是否启用
if l.svcCtx.YunYinSignPayService == nil {
logx.Errorf("云印签支付服务未启用")
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 解析表单数据
if err := r.ParseForm(); err != nil {
logx.Errorf("云印签回调,解析表单数据失败: %v", err)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 获取回调参数
tradeState := r.FormValue("tradeState")
orderType := r.FormValue("orderType")
payOrderNo := r.FormValue("payOrderNo")
payAmount := r.FormValue("payAmount")
flowId := r.FormValue("flowId")
sourceOrderCode := r.FormValue("sourceOrderCode")
channelOrderNo := r.FormValue("channelOrderNo")
paySuccessTime := r.FormValue("paySuccessTime")
// 记录回调日志
logx.Infof("云印签回调通知,订单号: %s, 支付状态: %s, 订单类型: %s, 支付单号: %s, 金额: %s, 流程ID: %s",
sourceOrderCode, tradeState, orderType, payOrderNo, payAmount, flowId)
// 只处理付款通知orderType == "pay"
if orderType != "pay" {
logx.Infof("云印签回调,非付款通知,订单类型: %s, 订单号: %s", orderType, sourceOrderCode)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 如果没有 sourceOrderCode无法关联订单直接返回成功
if sourceOrderCode == "" {
logx.Errorf("云印签回调,缺少 sourceOrderCode 参数")
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 根据 sourceOrderCode 查找订单
order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, sourceOrderCode)
if findOrderErr != nil {
logx.Errorf("云印签回调,查找订单失败,订单号: %s, 错误: %v", sourceOrderCode, findOrderErr)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 幂等性检查:如果订单已经不是 pending 状态,说明已经处理过,直接返回成功
if order.Status != "pending" {
logx.Infof("云印签回调,订单已处理,订单号: %s, 当前状态: %s", sourceOrderCode, order.Status)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 验证支付状态tradeState == "00000" 表示支付成功
if tradeState != "00000" {
logx.Infof("云印签回调,订单未支付成功,订单号: %s, 支付状态: %s", sourceOrderCode, tradeState)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 验证金额
payAmountFloat, parseAmountErr := strconv.ParseFloat(payAmount, 64)
if parseAmountErr != nil {
logx.Errorf("云印签回调,金额解析失败,订单号: %s, 金额: %s, 错误: %v", sourceOrderCode, payAmount, parseAmountErr)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 金额比较(允许小数点误差)
amountDiff := payAmountFloat - order.Amount
if amountDiff < 0 {
amountDiff = -amountDiff
}
if amountDiff > 0.01 { // 允许1分钱的误差
logx.Errorf("云印签回调,金额不一致,订单号: %s, 订单金额: %.2f, 回调金额: %.2f", sourceOrderCode, order.Amount, payAmountFloat)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 解析支付成功时间
var payTime time.Time
if paySuccessTime != "" {
// 尝试多种时间格式
timeFormats := []string{
"2006-01-02 15:04:05",
"2006-01-02T15:04:05",
"2006-01-02 15:04:05.000",
"2006-01-02T15:04:05.000Z",
}
parsed := false
for _, format := range timeFormats {
if t, err := time.Parse(format, paySuccessTime); err == nil {
payTime = t
parsed = true
break
}
}
if !parsed {
// 如果解析失败,使用当前时间
payTime = time.Now()
logx.Infof("云印签回调,支付时间解析失败,使用当前时间,订单号: %s, 时间字符串: %s", sourceOrderCode, paySuccessTime)
}
} else {
payTime = time.Now()
}
// 更新订单状态
order.Status = "paid"
order.PayTime = lzUtils.TimeToNullTime(payTime)
if channelOrderNo != "" {
order.PlatformOrderId = lzUtils.StringToNullString(channelOrderNo)
}
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
logx.Errorf("云印签回调,更新订单状态失败,订单号: %s, 错误: %v", sourceOrderCode, updateErr)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 更新云印签订单表的支付状态
yunyinOrder, findYunyinErr := l.svcCtx.YunyinSignPayOrderModel.FindOneByOrderId(l.ctx, order.Id)
if findYunyinErr == nil && yunyinOrder != nil {
// 更新支付状态为已支付1
if yunyinOrder.PayStatus != 1 {
yunyinOrder.PayStatus = 1
if _, updateYunyinErr := l.svcCtx.YunyinSignPayOrderModel.Update(l.ctx, nil, yunyinOrder); updateYunyinErr != nil {
logx.Errorf("云印签回调更新云印签订单支付状态失败订单ID: %s, 错误: %v", order.Id, updateYunyinErr)
} else {
logx.Infof("云印签回调成功更新云印签订单支付状态订单ID: %s", order.Id)
}
}
} else {
logx.Infof("云印签回调未找到对应的云印签订单记录订单ID: %s, 流程ID: %s", order.Id, flowId)
}
// 发送异步任务处理后续流程
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
logx.Errorf("云印签回调异步任务调度失败订单ID: %s, 错误: %v", order.Id, asyncErr)
// 不返回错误,因为订单已经更新成功
}
logx.Infof("云印签回调处理成功,订单号: %s, 支付单号: %s, 渠道单号: %s", sourceOrderCode, payOrderNo, channelOrderNo)
// 返回 success云印签要求返回纯字符串 success
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}