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

250 lines
11 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 {
logx.Infof("[云印签回调] 收到回调请求Method: %s, URL: %s, RemoteAddr: %s", r.Method, r.URL.String(), r.RemoteAddr)
logx.Infof("[云印签回调] 请求HeaderContent-Type: %s, User-Agent: %s", r.Header.Get("Content-Type"), r.Header.Get("User-Agent"))
// 检查云印签支付服务是否启用
if l.svcCtx.YunYinSignPayService == nil {
logx.Errorf("[云印签回调] 云印签支付服务未启用")
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
// 解析表单数据
logx.Infof("[云印签回调] 开始解析表单数据")
if err := r.ParseForm(); err != nil {
logx.Errorf("[云印签回调] 解析表单数据失败: %v", err)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
logx.Infof("[云印签回调] 表单数据解析成功Form参数数量: %d", len(r.Form))
// 获取回调参数
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("[云印签回调] 回调参数详情:")
logx.Infof("[云印签回调] - tradeState: %s", tradeState)
logx.Infof("[云印签回调] - orderType: %s", orderType)
logx.Infof("[云印签回调] - payOrderNo: %s", payOrderNo)
logx.Infof("[云印签回调] - payAmount: %s", payAmount)
logx.Infof("[云印签回调] - flowId: %s", flowId)
logx.Infof("[云印签回调] - sourceOrderCode: %s", sourceOrderCode)
logx.Infof("[云印签回调] - channelOrderNo: %s", channelOrderNo)
logx.Infof("[云印签回调] - paySuccessTime: %s", paySuccessTime)
// 记录回调日志
logx.Infof("[云印签回调] 回调通知摘要,订单号: %s, 支付状态: %s, 订单类型: %s, 支付单号: %s, 金额: %s, 流程ID: %s",
sourceOrderCode, tradeState, orderType, payOrderNo, payAmount, flowId)
// 只处理付款通知orderType == "pay"
logx.Infof("[云印签回调] 检查订单类型orderType: %s", orderType)
if orderType != "pay" {
logx.Infof("[云印签回调] 非付款通知,跳过处理,订单类型: %s, 订单号: %s", orderType, sourceOrderCode)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
logx.Infof("[云印签回调] 确认为付款通知,继续处理")
// 如果没有 sourceOrderCode无法关联订单直接返回成功
if sourceOrderCode == "" {
logx.Errorf("[云印签回调] 缺少 sourceOrderCode 参数,无法关联订单")
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
logx.Infof("[云印签回调] sourceOrderCode 存在,订单号: %s", sourceOrderCode)
// 根据 sourceOrderCode 查找订单
logx.Infof("[云印签回调] 开始查找订单,订单号: %s", 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
}
logx.Infof("[云印签回调] 订单查找成功,订单号: %s, 订单ID: %s, 订单状态: %s, 订单金额: %.2f, 支付平台: %s",
sourceOrderCode, order.Id, order.Status, order.Amount, order.PaymentPlatform)
// 幂等性检查:如果订单已经不是 pending 状态,说明已经处理过,直接返回成功
logx.Infof("[云印签回调] 幂等性检查,订单状态: %s", order.Status)
if order.Status != "pending" {
logx.Infof("[云印签回调] 订单已处理,跳过重复处理,订单号: %s, 当前状态: %s", sourceOrderCode, order.Status)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
logx.Infof("[云印签回调] 订单状态为pending继续处理")
// 验证支付状态tradeState == "00000" 表示支付成功
logx.Infof("[云印签回调] 验证支付状态tradeState: %s", tradeState)
if tradeState != "00000" {
logx.Infof("[云印签回调] 订单未支付成功,跳过处理,订单号: %s, 支付状态: %s", sourceOrderCode, tradeState)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
logx.Infof("[云印签回调] 支付状态验证通过tradeState: %s 表示支付成功", tradeState)
// 验证金额
logx.Infof("[云印签回调] 开始验证金额,回调金额字符串: %s, 订单金额: %.2f", payAmount, order.Amount)
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
}
logx.Infof("[云印签回调] 金额解析成功,回调金额: %.2f, 订单金额: %.2f", payAmountFloat, order.Amount)
// 金额比较(允许小数点误差)
amountDiff := payAmountFloat - order.Amount
if amountDiff < 0 {
amountDiff = -amountDiff
}
logx.Infof("[云印签回调] 金额差异: %.2f", amountDiff)
if amountDiff > 0.01 { // 允许1分钱的误差
logx.Errorf("[云印签回调] 金额不一致,订单号: %s, 订单金额: %.2f, 回调金额: %.2f, 差异: %.2f",
sourceOrderCode, order.Amount, payAmountFloat, amountDiff)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
logx.Infof("[云印签回调] 金额验证通过,差异在允许范围内")
// 解析支付成功时间
logx.Infof("[云印签回调] 开始解析支付成功时间,时间字符串: %s", paySuccessTime)
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 i, format := range timeFormats {
if t, err := time.Parse(format, paySuccessTime); err == nil {
payTime = t
parsed = true
logx.Infof("[云印签回调] 支付时间解析成功,使用格式[%d]: %s, 解析结果: %s", i, format, payTime.Format("2006-01-02 15:04:05"))
break
}
}
if !parsed {
// 如果解析失败,使用当前时间
payTime = time.Now()
logx.Infof("[云印签回调] 支付时间解析失败,使用当前时间,订单号: %s, 时间字符串: %s, 当前时间: %s",
sourceOrderCode, paySuccessTime, payTime.Format("2006-01-02 15:04:05"))
}
} else {
payTime = time.Now()
logx.Infof("[云印签回调] 支付时间字符串为空,使用当前时间: %s", payTime.Format("2006-01-02 15:04:05"))
}
// 更新订单状态
logx.Infof("[云印签回调] 开始更新订单状态,订单号: %s, 订单ID: %s, 原状态: %s, 新状态: paid, 支付时间: %s, 渠道单号: %s",
sourceOrderCode, order.Id, order.Status, payTime.Format("2006-01-02 15:04:05"), channelOrderNo)
order.Status = "paid"
order.PayTime = lzUtils.TimeToNullTime(payTime)
if channelOrderNo != "" {
order.PlatformOrderId = lzUtils.StringToNullString(channelOrderNo)
logx.Infof("[云印签回调] 设置渠道单号,订单号: %s, 渠道单号: %s", sourceOrderCode, channelOrderNo)
}
logx.Infof("[云印签回调] 调用UpdateWithVersion更新订单订单号: %s, 订单ID: %s, Version: %d",
sourceOrderCode, order.Id, order.Version)
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
logx.Errorf("[云印签回调] 更新订单状态失败,订单号: %s, 订单ID: %s, 错误: %v", sourceOrderCode, order.Id, updateErr)
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}
logx.Infof("[云印签回调] 订单状态更新成功,订单号: %s, 订单ID: %s", sourceOrderCode, order.Id)
// 更新云印签订单表的支付状态
logx.Infof("[云印签回调] 开始查找云印签订单记录订单ID: %s, 流程ID: %s", order.Id, flowId)
yunyinOrder, findYunyinErr := l.svcCtx.YunyinSignPayOrderModel.FindOneByOrderId(l.ctx, order.Id)
if findYunyinErr == nil && yunyinOrder != nil {
logx.Infof("[云印签回调] 找到云印签订单记录订单ID: %s, 云印签订单ID: %s, 任务ID: %s, 参与者ID: %s, 当前支付状态: %d",
order.Id, yunyinOrder.Id, yunyinOrder.TaskId, yunyinOrder.ParticipantId, yunyinOrder.PayStatus)
// 更新支付状态为已支付1
if yunyinOrder.PayStatus != 1 {
logx.Infof("[云印签回调] 需要更新云印签订单支付状态订单ID: %s, 原支付状态: %d, 新支付状态: 1", order.Id, yunyinOrder.PayStatus)
yunyinOrder.PayStatus = 1
if _, updateYunyinErr := l.svcCtx.YunyinSignPayOrderModel.Update(l.ctx, nil, yunyinOrder); updateYunyinErr != nil {
logx.Errorf("[云印签回调] 更新云印签订单支付状态失败订单ID: %s, 云印签订单ID: %s, 错误: %v",
order.Id, yunyinOrder.Id, updateYunyinErr)
} else {
logx.Infof("[云印签回调] 成功更新云印签订单支付状态订单ID: %s, 云印签订单ID: %s, 支付状态: 1",
order.Id, yunyinOrder.Id)
}
} else {
logx.Infof("[云印签回调] 云印签订单支付状态已是已支付无需更新订单ID: %s, 支付状态: %d", order.Id, yunyinOrder.PayStatus)
}
} else {
if findYunyinErr != nil {
logx.Infof("[云印签回调] 查找云印签订单记录失败订单ID: %s, 流程ID: %s, 错误: %v", order.Id, flowId, findYunyinErr)
} else {
logx.Infof("[云印签回调] 未找到对应的云印签订单记录订单ID: %s, 流程ID: %s", order.Id, flowId)
}
}
// 发送异步任务处理后续流程
logx.Infof("[云印签回调] 开始发送异步任务订单ID: %s", order.Id)
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
logx.Errorf("[云印签回调] 异步任务调度失败订单ID: %s, 错误: %v", order.Id, asyncErr)
// 不返回错误,因为订单已经更新成功
} else {
logx.Infof("[云印签回调] 异步任务发送成功订单ID: %s", order.Id)
}
logx.Infof("[云印签回调] 回调处理完成,订单号: %s, 订单ID: %s, 支付单号: %s, 渠道单号: %s, 支付金额: %.2f",
sourceOrderCode, order.Id, payOrderNo, channelOrderNo, payAmountFloat)
// 返回 success云印签要求返回纯字符串 success
logx.Infof("[云印签回调] 返回success响应给云印签")
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
return nil
}