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 }