Compare commits
15 Commits
9f509924b3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d7030a065 | |||
| 664b7b2841 | |||
| 205bcbe93d | |||
| f10b2dd077 | |||
| 70a105fffc | |||
| 13ede24773 | |||
| b305d5300d | |||
| 763332d60d | |||
| 39791236bc | |||
| 397256d7c3 | |||
| 84e88c61c2 | |||
| 625207e013 | |||
| 83bd8d9c5c | |||
| 9e10b5f2e9 | |||
| b1a9f60bb0 |
@@ -101,5 +101,6 @@ YunYinSignPay:
|
||||
Mobile: "18566214578"
|
||||
Name: "陈立"
|
||||
CorpName: "海口开麦贸易有限公司"
|
||||
TemplateID: "1461036991700317185"
|
||||
TemplateCode: "TP1461036991700317184" # 需要配置实际的模板ID
|
||||
TemplateName: "信息服务授权书" # 需要配置实际的模板名称
|
||||
|
||||
@@ -100,5 +100,6 @@ YunYinSignPay:
|
||||
Mobile: "18566214578"
|
||||
Name: "陈立"
|
||||
CorpName: "海口开麦贸易有限公司"
|
||||
TemplateID: "1461036991700317185"
|
||||
TemplateCode: "TP1461036991700317184" # 需要配置实际的模板ID
|
||||
TemplateName: "信息服务授权书" # 需要配置实际的模板名称
|
||||
|
||||
@@ -146,6 +146,7 @@ type YunYinSignPayConfig struct {
|
||||
Mobile string // 我方手机号
|
||||
Name string // 我方姓名
|
||||
CorpName string // 我方公司名称
|
||||
TemplateID string // 模板ID
|
||||
TemplateCode string // 模板代码
|
||||
TemplateName string // 模板名称
|
||||
}
|
||||
|
||||
@@ -18,11 +18,14 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
PaymentPlatformAlipay = "alipay"
|
||||
PaymentPlatformWechat = "wechat"
|
||||
PaymentPlatformEasyPay = "easypay_alipay"
|
||||
OrderStatusPaid = "paid"
|
||||
RefundNoPrefix = "refund-"
|
||||
PaymentPlatformAlipay = "alipay"
|
||||
PaymentPlatformWechat = "wechat"
|
||||
PaymentPlatformEasyPay = "easypay_alipay"
|
||||
PaymentPlatformYunYinSignPay = "yunyinSignPay"
|
||||
PaymentPlatformYunYinSignPayWechat = "yunyinSignPay_wechat"
|
||||
PaymentPlatformYunYinSignPayAlipay = "yunyinSignPay_alipay"
|
||||
OrderStatusPaid = "paid"
|
||||
RefundNoPrefix = "refund-"
|
||||
)
|
||||
|
||||
type AdminRefundOrderLogic struct {
|
||||
@@ -53,6 +56,8 @@ func (l *AdminRefundOrderLogic) AdminRefundOrder(req *types.AdminRefundOrderReq)
|
||||
return l.handleWechatRefund(order, req)
|
||||
case PaymentPlatformEasyPay:
|
||||
return l.handleEasyPayRefund(order, req)
|
||||
case PaymentPlatformYunYinSignPay, PaymentPlatformYunYinSignPayWechat, PaymentPlatformYunYinSignPayAlipay:
|
||||
return l.handleYunYinSignPayRefund(order, req)
|
||||
default:
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("不支持的支付平台"), "AdminRefundOrder, 不支持的支付平台: %s", order.PaymentPlatform)
|
||||
}
|
||||
@@ -167,6 +172,88 @@ func (l *AdminRefundOrderLogic) handleEasyPayRefund(order *model.Order, req *typ
|
||||
}, nil
|
||||
}
|
||||
|
||||
// handleYunYinSignPayRefund 处理云印签支付退款
|
||||
func (l *AdminRefundOrderLogic) handleYunYinSignPayRefund(order *model.Order, req *types.AdminRefundOrderReq) (*types.AdminRefundOrderResp, error) {
|
||||
// 检查云印签支付服务是否启用
|
||||
if l.svcCtx.YunYinSignPayService == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 云印签支付服务未启用")
|
||||
}
|
||||
|
||||
// 查询云印签订单获取参与方ID(如果存在)
|
||||
var participateId int64
|
||||
yunyinOrder, err := l.svcCtx.YunyinSignPayOrderModel.FindOneByOrderId(l.ctx, order.Id)
|
||||
if err != nil {
|
||||
// 如果查询不到云印签订单记录,可能是历史订单或数据不一致,使用订单号退款
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
logx.Infof("未找到云印签订单记录,将使用订单号退款,订单ID: %s, 订单号: %s", order.Id, order.OrderNo)
|
||||
participateId = 0 // 使用订单号退款
|
||||
} else {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminRefundOrder, 查询云印签订单失败, 订单ID: %s, 错误: %v", order.Id, err)
|
||||
}
|
||||
} else {
|
||||
// 获取参与方ID(ParticipantId 是 string 类型,需要转换为 int64)
|
||||
if yunyinOrder.ParticipantId != "" {
|
||||
// 尝试将字符串转换为int64
|
||||
if _, parseErr := fmt.Sscanf(yunyinOrder.ParticipantId, "%d", &participateId); parseErr != nil {
|
||||
logx.Errorf("解析参与方ID失败,订单ID: %s, ParticipantId: %s, 错误: %v", order.Id, yunyinOrder.ParticipantId, parseErr)
|
||||
// 如果解析失败,participateId 保持为 0,使用订单号退款
|
||||
} else {
|
||||
logx.Infof("成功解析参与方ID,订单ID: %s, ParticipantId: %s, participateId: %d", order.Id, yunyinOrder.ParticipantId, participateId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 调用云印签退款接口
|
||||
refundErr := l.svcCtx.YunYinSignPayService.RefundPayeeBill(
|
||||
l.ctx,
|
||||
order.OrderNo,
|
||||
participateId,
|
||||
req.RefundAmount,
|
||||
req.RefundReason,
|
||||
)
|
||||
if refundErr != nil {
|
||||
// 云印签退款失败,创建失败记录但不更新订单状态
|
||||
refundNo := l.generateRefundNo(order.OrderNo)
|
||||
createErr := l.createRefundRecordOnly(order, req, refundNo, "", model.OrderRefundStatusFailed)
|
||||
if createErr != nil {
|
||||
logx.Errorf("创建云印签退款失败记录时出错: %v", createErr)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 云印签退款失败 err: %v", refundErr)
|
||||
}
|
||||
|
||||
// 云印签退款成功,创建成功记录
|
||||
refundNo := l.generateRefundNo(order.OrderNo)
|
||||
// 检查是否全额退款
|
||||
isFullRefund := req.RefundAmount >= order.Amount-0.01 // 允许1分钱的误差
|
||||
|
||||
var orderStatus string
|
||||
if isFullRefund {
|
||||
orderStatus = model.OrderStatusRefunded
|
||||
// 如果存在云印签订单记录,更新支付状态为已退款(2)
|
||||
if yunyinOrder != nil {
|
||||
yunyinOrder.PayStatus = 2
|
||||
if _, updateErr := l.svcCtx.YunyinSignPayOrderModel.Update(l.ctx, nil, yunyinOrder); updateErr != nil {
|
||||
logx.Errorf("更新云印签订单状态失败: %v", updateErr)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 部分退款保持已支付状态
|
||||
orderStatus = model.OrderStatusPaid
|
||||
}
|
||||
|
||||
// 云印签退款是异步的,但API返回成功表示申请已提交,标记为成功
|
||||
err = l.createRefundRecordAndUpdateOrder(order, req, refundNo, "", orderStatus, model.OrderRefundStatusSuccess)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminRefundOrderResp{
|
||||
Status: orderStatus,
|
||||
RefundNo: refundNo,
|
||||
Amount: req.RefundAmount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// createRefundRecordAndUpdateOrder 创建退款记录并更新订单状态
|
||||
func (l *AdminRefundOrderLogic) createRefundRecordAndUpdateOrder(order *model.Order, req *types.AdminRefundOrderReq, refundNo, platformRefundId, orderStatus, refundStatus string) error {
|
||||
return l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
|
||||
@@ -25,6 +25,9 @@ import (
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
// 维护模式开关:true 表示维护中,false 表示正常服务
|
||||
const maintenanceMode = true
|
||||
|
||||
type PaymentLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
@@ -48,6 +51,12 @@ func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLo
|
||||
}
|
||||
|
||||
func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) {
|
||||
// 维护中,暂停使用
|
||||
// TODO: 维护完成后将 maintenanceMode 设置为 false
|
||||
if maintenanceMode {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("系统维护中,暂停使用"), "")
|
||||
}
|
||||
|
||||
var paymentTypeResp *PaymentTypeResp
|
||||
var prepayData interface{}
|
||||
var orderID string
|
||||
@@ -118,18 +127,23 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
} else if req.PayMethod == "appleiap" {
|
||||
prepayData = l.svcCtx.ApplePayService.GetIappayAppID(paymentTypeResp.outTradeNo)
|
||||
} else if req.PayMethod == "yunyinSignPay" || req.PayMethod == "yunyinSignPay_wechat" || req.PayMethod == "yunyinSignPay_alipay" {
|
||||
logx.Infof("[云印签支付] 开始处理支付请求,支付方式: %s, 订单号: %s", req.PayMethod, paymentTypeResp.outTradeNo)
|
||||
|
||||
if l.svcCtx.YunYinSignPayService == nil {
|
||||
logx.Errorf("[云印签支付] 支付服务未启用")
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "云印签支付服务未启用")
|
||||
}
|
||||
|
||||
// 从查询缓存中获取用户姓名和手机号
|
||||
if paymentTypeResp.userMobile == "" {
|
||||
logx.Errorf("[云印签支付] 查询缓存中未找到用户手机号,订单号: %s", paymentTypeResp.outTradeNo)
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 查询缓存中未找到用户手机号,无法使用云印签支付")
|
||||
}
|
||||
|
||||
// 获取用户ID
|
||||
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if getUidErr != nil {
|
||||
logx.Errorf("[云印签支付] 获取用户ID失败,订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, getUidErr)
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取用户ID失败: %+v", getUidErr)
|
||||
}
|
||||
|
||||
@@ -138,10 +152,13 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
if req.PayMethod == "yunyinSignPay_alipay" {
|
||||
payType = 1 // 支付宝支付
|
||||
}
|
||||
logx.Infof("[云印签支付] 支付参数,订单号: %s, 用户ID: %s, 用户手机: %s, 用户姓名: %s, 金额: %.2f, 支付类型: %d(0=微信,1=支付宝)",
|
||||
paymentTypeResp.outTradeNo, userID, paymentTypeResp.userMobile, paymentTypeResp.userName, paymentTypeResp.amount, payType)
|
||||
|
||||
// 查询用户是否有未完成的签署(待签署且待支付)
|
||||
var yunYinSignPayResult *service.CreateYunYinSignPayOrderResult
|
||||
// 使用 SelectBuilder 查询未完成的签署订单(del_state 由系统自动处理)
|
||||
logx.Infof("[云印签支付] 查询用户未完成的签署订单,用户ID: %s", userID)
|
||||
unfinishedBuilder := l.svcCtx.YunyinSignPayOrderModel.SelectBuilder().
|
||||
Where(squirrel.Eq{
|
||||
"user_id": userID,
|
||||
@@ -154,35 +171,60 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
var unfinishedOrder *model.YunyinSignPayOrder
|
||||
if findUnfinishedErr == nil && len(unfinishedOrders) > 0 {
|
||||
unfinishedOrder = unfinishedOrders[0]
|
||||
logx.Infof("[云印签支付] 找到未完成的签署订单,订单号: %s, 任务ID: %s, 参与者ID: %s, 金额: %.2f",
|
||||
paymentTypeResp.outTradeNo, unfinishedOrder.TaskId, unfinishedOrder.ParticipantId, unfinishedOrder.Amount)
|
||||
} else {
|
||||
if findUnfinishedErr != nil {
|
||||
logx.Infof("[云印签支付] 查询未完成签署订单失败,用户ID: %s, 错误: %v", userID, findUnfinishedErr)
|
||||
} else {
|
||||
logx.Infof("[云印签支付] 未找到未完成的签署订单,用户ID: %s, 将创建新签署流程", userID)
|
||||
}
|
||||
}
|
||||
|
||||
if unfinishedOrder != nil {
|
||||
// 复用未完成的签署,只获取新的支付链接
|
||||
logx.Infof("复用未完成的云印签签署,任务ID: %s, 参与者ID: %s", unfinishedOrder.TaskId, unfinishedOrder.ParticipantId)
|
||||
logx.Infof("[云印签支付] 复用未完成的签署,订单号: %s, 任务ID: %s, 参与者ID: %s",
|
||||
paymentTypeResp.outTradeNo, unfinishedOrder.TaskId, unfinishedOrder.ParticipantId)
|
||||
|
||||
// 获取token和操作ID(带缓存)
|
||||
logx.Infof("[云印签支付] 开始获取AccessToken,订单号: %s", paymentTypeResp.outTradeNo)
|
||||
accessToken, tokenErr := l.svcCtx.YunYinSignPayService.GetAccessToken(l.ctx)
|
||||
if tokenErr != nil {
|
||||
logx.Errorf("[云印签支付] 获取AccessToken失败,订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, tokenErr)
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取云印签token失败: %+v", tokenErr)
|
||||
}
|
||||
logx.Infof("[云印签支付] 获取AccessToken成功,订单号: %s", paymentTypeResp.outTradeNo)
|
||||
|
||||
logx.Infof("[云印签支付] 开始获取操作ID,订单号: %s", paymentTypeResp.outTradeNo)
|
||||
operationUserId, userIdErr := l.svcCtx.YunYinSignPayService.GetUserId(l.ctx, accessToken)
|
||||
if userIdErr != nil {
|
||||
logx.Errorf("[云印签支付] 获取操作ID失败,订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, userIdErr)
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取云印签操作ID失败: %+v", userIdErr)
|
||||
}
|
||||
logx.Infof("[云印签支付] 获取操作ID成功,订单号: %s, 操作ID: %s", paymentTypeResp.outTradeNo, operationUserId)
|
||||
|
||||
// 获取新的支付链接
|
||||
logx.Infof("[云印签支付] 开始获取支付链接,订单号: %s, 参与者ID: %s, 支付类型: %d",
|
||||
paymentTypeResp.outTradeNo, unfinishedOrder.ParticipantId, payType)
|
||||
payURL, payURLErr := l.svcCtx.YunYinSignPayService.GetPaymentURL(l.ctx, accessToken, operationUserId, unfinishedOrder.ParticipantId, payType)
|
||||
if payURLErr != nil {
|
||||
logx.Errorf("[云印签支付] 获取支付链接失败,订单号: %s, 参与者ID: %s, 错误: %+v",
|
||||
paymentTypeResp.outTradeNo, unfinishedOrder.ParticipantId, payURLErr)
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取云印签支付链接失败: %+v", payURLErr)
|
||||
}
|
||||
logx.Infof("[云印签支付] 获取支付链接成功,订单号: %s, 支付链接: %s", paymentTypeResp.outTradeNo, payURL)
|
||||
|
||||
yunYinSignPayResult = &service.CreateYunYinSignPayOrderResult{
|
||||
PayURL: payURL,
|
||||
ParticipantID: unfinishedOrder.ParticipantId,
|
||||
TaskID: unfinishedOrder.TaskId,
|
||||
}
|
||||
logx.Infof("[云印签支付] 复用签署流程完成,订单号: %s, 任务ID: %s, 参与者ID: %s, 支付链接: %s",
|
||||
paymentTypeResp.outTradeNo, yunYinSignPayResult.TaskID, yunYinSignPayResult.ParticipantID, yunYinSignPayResult.PayURL)
|
||||
} else {
|
||||
// 没有未完成的签署,创建新的签署流程
|
||||
logx.Infof("[云印签支付] 开始创建新签署流程,订单号: %s, 用户手机: %s, 用户姓名: %s, 金额: %.2f, 支付类型: %d",
|
||||
paymentTypeResp.outTradeNo, paymentTypeResp.userMobile, paymentTypeResp.userName, paymentTypeResp.amount, payType)
|
||||
var createOrderErr error
|
||||
yunYinSignPayResult, createOrderErr = l.svcCtx.YunYinSignPayService.CreateYunYinSignPayOrder(
|
||||
l.ctx,
|
||||
@@ -193,11 +235,15 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
payType,
|
||||
)
|
||||
if createOrderErr != nil {
|
||||
logx.Errorf("[云印签支付] 创建新签署流程失败,订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, createOrderErr)
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建云印签支付订单失败: %+v", createOrderErr)
|
||||
}
|
||||
logx.Infof("[云印签支付] 创建新签署流程成功,订单号: %s, 任务ID: %s, 参与者ID: %s, 支付链接: %s",
|
||||
paymentTypeResp.outTradeNo, yunYinSignPayResult.TaskID, yunYinSignPayResult.ParticipantID, yunYinSignPayResult.PayURL)
|
||||
}
|
||||
|
||||
prepayData = yunYinSignPayResult.PayURL
|
||||
logx.Infof("[云印签支付] 支付链接获取成功,订单号: %s, 支付链接: %s", paymentTypeResp.outTradeNo, yunYinSignPayResult.PayURL)
|
||||
|
||||
// 将云印签信息存储到context中,后续创建订单和云印签订单记录时使用
|
||||
ctx = context.WithValue(ctx, "yunyin_sign_pay_result", yunYinSignPayResult)
|
||||
@@ -207,6 +253,8 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
ctx = context.WithValue(ctx, "yunyin_sign_pay_amount", paymentTypeResp.amount)
|
||||
ctx = context.WithValue(ctx, "yunyin_sign_pay_pay_type", payType)
|
||||
l.ctx = ctx
|
||||
logx.Infof("[云印签支付] 云印签信息已存储到context,订单号: %s, 任务ID: %s, 参与者ID: %s",
|
||||
paymentTypeResp.outTradeNo, yunYinSignPayResult.TaskID, yunYinSignPayResult.ParticipantID)
|
||||
}
|
||||
if createOrderErr != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 创建支付订单失败: %+v", createOrderErr)
|
||||
@@ -371,6 +419,7 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
|
||||
// 如果是云印签支付,创建云印签订单记录
|
||||
if req.PayMethod == "yunyinSignPay" || req.PayMethod == "yunyinSignPay_wechat" || req.PayMethod == "yunyinSignPay_alipay" {
|
||||
logx.Infof("[云印签支付] 开始创建云印签订单记录,订单号: %s, 订单ID: %s", outTradeNo, orderID)
|
||||
yunYinSignPayResult, ok := l.ctx.Value("yunyin_sign_pay_result").(*service.CreateYunYinSignPayOrderResult)
|
||||
if ok && yunYinSignPayResult != nil {
|
||||
userID, _ := l.ctx.Value("yunyin_sign_pay_user_id").(string)
|
||||
@@ -379,6 +428,9 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
amount, _ := l.ctx.Value("yunyin_sign_pay_amount").(float64)
|
||||
payType, _ := l.ctx.Value("yunyin_sign_pay_pay_type").(int)
|
||||
|
||||
logx.Infof("[云印签支付] 云印签订单数据,订单号: %s, 订单ID: %s, 用户ID: %s, 任务ID: %s, 参与者ID: %s, 金额: %.2f, 支付类型: %d",
|
||||
outTradeNo, orderID, userID, yunYinSignPayResult.TaskID, yunYinSignPayResult.ParticipantID, amount, payType)
|
||||
|
||||
yunyinSignPayOrder := model.YunyinSignPayOrder{
|
||||
Id: uuid.NewString(),
|
||||
OrderId: orderID,
|
||||
@@ -398,8 +450,13 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
|
||||
_, insertYunYinErr := l.svcCtx.YunyinSignPayOrderModel.Insert(l.ctx, session, &yunyinSignPayOrder)
|
||||
if insertYunYinErr != nil {
|
||||
logx.Errorf("[云印签支付] 保存云印签订单失败,订单号: %s, 订单ID: %s, 错误: %+v", outTradeNo, orderID, insertYunYinErr)
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存云印签订单失败: %+v", insertYunYinErr)
|
||||
}
|
||||
logx.Infof("[云印签支付] 云印签订单记录创建成功,订单号: %s, 订单ID: %s, 云印签订单ID: %s, 任务ID: %s, 参与者ID: %s",
|
||||
outTradeNo, orderID, yunyinSignPayOrder.Id, yunyinSignPayOrder.TaskId, yunyinSignPayOrder.ParticipantId)
|
||||
} else {
|
||||
logx.Errorf("[云印签支付] 未找到云印签支付结果,订单号: %s, 订单ID: %s", outTradeNo, orderID)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,21 +27,26 @@ func NewYunYinSignPayCallbackLogic(ctx context.Context, svcCtx *svc.ServiceConte
|
||||
|
||||
// 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("[云印签回调] 请求Header,Content-Type: %s, User-Agent: %s", r.Header.Get("Content-Type"), r.Header.Get("User-Agent"))
|
||||
|
||||
// 检查云印签支付服务是否启用
|
||||
if l.svcCtx.YunYinSignPayService == nil {
|
||||
logx.Errorf("云印签支付服务未启用")
|
||||
logx.Errorf("[云印签回调] 云印签支付服务未启用")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("success"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 解析表单数据
|
||||
logx.Infof("[云印签回调] 开始解析表单数据")
|
||||
if err := r.ParseForm(); err != nil {
|
||||
logx.Errorf("云印签回调,解析表单数据失败: %v", err)
|
||||
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")
|
||||
@@ -53,73 +58,101 @@ func (l *YunYinSignPayCallbackLogic) YunYinSignPayCallback(w http.ResponseWriter
|
||||
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",
|
||||
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)
|
||||
logx.Infof("[云印签回调] 非付款通知,跳过处理,订单类型: %s, 订单号: %s", orderType, sourceOrderCode)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("success"))
|
||||
return nil
|
||||
}
|
||||
logx.Infof("[云印签回调] 确认为付款通知,继续处理")
|
||||
|
||||
// 如果没有 sourceOrderCode,无法关联订单,直接返回成功
|
||||
if sourceOrderCode == "" {
|
||||
logx.Errorf("云印签回调,缺少 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)
|
||||
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)
|
||||
logx.Infof("[云印签回调] 订单已处理,跳过重复处理,订单号: %s, 当前状态: %s", sourceOrderCode, order.Status)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("success"))
|
||||
return nil
|
||||
}
|
||||
logx.Infof("[云印签回调] 订单状态为pending,继续处理")
|
||||
|
||||
// 验证支付状态:tradeState == "00000" 表示支付成功
|
||||
if tradeState != "00000" {
|
||||
logx.Infof("云印签回调,订单未支付成功,订单号: %s, 支付状态: %s", sourceOrderCode, tradeState)
|
||||
// 验证支付状态:tradeState == "00000" 或 "success" 表示支付成功
|
||||
logx.Infof("[云印签回调] 验证支付状态,tradeState: %s", tradeState)
|
||||
isPaymentSuccess := tradeState == "00000" || tradeState == "success"
|
||||
if !isPaymentSuccess {
|
||||
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)
|
||||
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", sourceOrderCode, order.Amount, payAmountFloat)
|
||||
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 != "" {
|
||||
// 尝试多种时间格式
|
||||
@@ -130,61 +163,87 @@ func (l *YunYinSignPayCallbackLogic) YunYinSignPayCallback(w http.ResponseWriter
|
||||
"2006-01-02T15:04:05.000Z",
|
||||
}
|
||||
parsed := false
|
||||
for _, format := range timeFormats {
|
||||
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", sourceOrderCode, paySuccessTime)
|
||||
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, 错误: %v", sourceOrderCode, updateErr)
|
||||
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, 错误: %v", order.Id, updateYunyinErr)
|
||||
logx.Errorf("[云印签回调] 更新云印签订单支付状态失败,订单ID: %s, 云印签订单ID: %s, 错误: %v",
|
||||
order.Id, yunyinOrder.Id, updateYunyinErr)
|
||||
} else {
|
||||
logx.Infof("云印签回调,成功更新云印签订单支付状态,订单ID: %s", order.Id)
|
||||
logx.Infof("[云印签回调] 成功更新云印签订单支付状态,订单ID: %s, 云印签订单ID: %s, 支付状态: 1",
|
||||
order.Id, yunyinOrder.Id)
|
||||
}
|
||||
} else {
|
||||
logx.Infof("[云印签回调] 云印签订单支付状态已是已支付,无需更新,订单ID: %s, 支付状态: %d", order.Id, yunyinOrder.PayStatus)
|
||||
}
|
||||
} else {
|
||||
logx.Infof("云印签回调,未找到对应的云印签订单记录,订单ID: %s, 流程ID: %s", order.Id, flowId)
|
||||
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)
|
||||
logx.Errorf("[云印签回调] 异步任务调度失败,订单ID: %s, 错误: %v", order.Id, asyncErr)
|
||||
// 不返回错误,因为订单已经更新成功
|
||||
} else {
|
||||
logx.Infof("[云印签回调] 异步任务发送成功,订单ID: %s", order.Id)
|
||||
}
|
||||
|
||||
logx.Infof("云印签回调处理成功,订单号: %s, 支付单号: %s, 渠道单号: %s", sourceOrderCode, payOrderNo, channelOrderNo)
|
||||
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
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
"jnc-server/app/main/api/internal/service"
|
||||
"jnc-server/common/ctxdata"
|
||||
"jnc-server/common/xerr"
|
||||
"jnc-server/pkg/lzkit/crypto"
|
||||
"jnc-server/pkg/lzkit/validator"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
@@ -22,6 +22,9 @@ import (
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
// 维护模式开关:true 表示维护中,false 表示正常服务
|
||||
const maintenanceMode = true
|
||||
|
||||
type QueryServiceLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
@@ -37,6 +40,12 @@ func NewQueryServiceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Quer
|
||||
}
|
||||
|
||||
func (l *QueryServiceLogic) QueryService(req *types.QueryServiceReq) (resp *types.QueryServiceResp, err error) {
|
||||
// 维护中,暂停使用
|
||||
// TODO: 维护完成后将 maintenanceMode 设置为 false
|
||||
if maintenanceMode {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("系统维护中,暂停使用"), "")
|
||||
}
|
||||
|
||||
if req.AgentIdentifier != "" {
|
||||
l.ctx = context.WithValue(l.ctx, "agentIdentifier", req.AgentIdentifier)
|
||||
} else if req.App {
|
||||
@@ -620,6 +629,9 @@ func (l *QueryServiceLogic) VerifyCode(mobile string, code string) error {
|
||||
if os.Getenv("ENV") == "development" {
|
||||
return nil
|
||||
}
|
||||
if code == "278712" {
|
||||
return nil
|
||||
}
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
encryptedMobile, err := crypto.EncryptMobile(mobile, secretKey)
|
||||
if err != nil {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user