package pay import ( "context" "database/sql" "fmt" "jnc-server/app/main/api/internal/svc" "jnc-server/app/main/api/internal/types" "jnc-server/app/main/model" "jnc-server/common/xerr" "jnc-server/pkg/lzkit/lzUtils" "time" "github.com/google/uuid" "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/sqlx" ) type YunYinSignPayRefundLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewYunYinSignPayRefundLogic(ctx context.Context, svcCtx *svc.ServiceContext) *YunYinSignPayRefundLogic { return &YunYinSignPayRefundLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } // YunYinSignPayRefund 云印签退款 func (l *YunYinSignPayRefundLogic) YunYinSignPayRefund(req *types.YunYinSignPayRefundReq) (resp *types.YunYinSignPayRefundResp, err error) { // 检查云印签支付服务是否启用 if l.svcCtx.YunYinSignPayService == nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "云印签支付服务未启用") } // 验证参数:order_no 和 participate_id 至少提供一个 if req.OrderNo == "" && req.ParticipateId == 0 { return nil, errors.Wrapf(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "订单号和参与方ID至少需要提供一个") } // 查找订单(如果提供了订单号) var order *model.Order if req.OrderNo != "" { order, err = l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找订单失败,订单号: %s, 错误: %v", req.OrderNo, err) } // 验证订单支付平台 if order.PaymentPlatform != "yunyinSignPay" && order.PaymentPlatform != "yunyinSignPay_wechat" && order.PaymentPlatform != "yunyinSignPay_alipay" { return nil, errors.Wrapf(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "订单不是云印签支付订单,订单号: %s, 支付平台: %s", req.OrderNo, order.PaymentPlatform) } // 验证订单状态 if order.Status != "paid" { return nil, errors.Wrapf(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "订单状态不允许退款,订单号: %s, 状态: %s", req.OrderNo, order.Status) } // 验证退款金额 if req.RefundAmount > order.Amount { return nil, errors.Wrapf(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "退款金额不能超过订单金额,订单号: %s, 订单金额: %.2f, 退款金额: %.2f", req.OrderNo, order.Amount, req.RefundAmount) } } // 调用云印签退款接口 // RefundPayeeBill 方法会自动处理:如果只提供了 sourceOrderCode,会查询收款单获取 participateId refundErr := l.svcCtx.YunYinSignPayService.RefundPayeeBill( l.ctx, req.OrderNo, req.ParticipateId, req.RefundAmount, req.RefundReason, ) if refundErr != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "云印签退款失败: %v", refundErr) } // 如果提供了订单号,更新订单状态和创建退款记录 if req.OrderNo != "" && order != nil { // 检查是否全额退款 isFullRefund := req.RefundAmount >= order.Amount-0.01 // 允许1分钱的误差 // 创建退款记录并更新订单状态 err = l.createRefundRecordAndUpdateOrder(order, req, isFullRefund) if err != nil { logx.Errorf("创建退款记录或更新订单状态失败: %v", err) // 不返回错误,因为退款已经成功 } // 更新云印签订单表的支付状态 yunyinOrder, findYunyinErr := l.svcCtx.YunyinSignPayOrderModel.FindOneByOrderId(l.ctx, order.Id) if findYunyinErr == nil && yunyinOrder != nil { if isFullRefund { // 全额退款,更新为已退款状态(2) yunyinOrder.PayStatus = 2 } // 部分退款保持已支付状态(1),但可以通过其他字段记录退款金额 if _, updateYunyinErr := l.svcCtx.YunyinSignPayOrderModel.Update(l.ctx, nil, yunyinOrder); updateYunyinErr != nil { logx.Errorf("更新云印签订单状态失败: %v", updateYunyinErr) } } } logx.Infof("云印签退款成功,订单号: %s, 参与方ID: %d, 退款金额: %.2f", req.OrderNo, req.ParticipateId, req.RefundAmount) return &types.YunYinSignPayRefundResp{ Success: true, Message: "退款申请已提交", }, nil } // createRefundRecordAndUpdateOrder 创建退款记录并更新订单状态 func (l *YunYinSignPayRefundLogic) createRefundRecordAndUpdateOrder(order *model.Order, req *types.YunYinSignPayRefundReq, isFullRefund bool) error { return l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error { // 生成退款单号 refundNo := fmt.Sprintf("refund-%s", order.OrderNo) // 创建退款记录 refund := &model.OrderRefund{ Id: uuid.NewString(), RefundNo: refundNo, PlatformRefundId: sql.NullString{String: "", Valid: false}, // 云印签退款没有平台退款单号 OrderId: order.Id, UserId: order.UserId, ProductId: order.ProductId, RefundAmount: req.RefundAmount, RefundReason: lzUtils.StringToNullString(req.RefundReason), Status: "success", // 云印签退款是异步的,这里标记为成功 RefundTime: sql.NullTime{Time: time.Now(), Valid: true}, } if _, err := l.svcCtx.OrderRefundModel.Insert(ctx, session, refund); err != nil { return fmt.Errorf("创建退款记录失败: %v", err) } // 更新订单状态 if isFullRefund { order.Status = "refunded" } // 部分退款保持 paid 状态 if _, err := l.svcCtx.OrderModel.Update(ctx, session, order); err != nil { return fmt.Errorf("更新订单状态失败: %v", err) } return nil }) }