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