Files
sim-server/app/main/api/internal/logic/pay/yunyinsignpayrefundlogic.go
2026-02-08 16:19:37 +08:00

154 lines
5.6 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"
"database/sql"
"fmt"
"sim-server/app/main/api/internal/svc"
"sim-server/app/main/api/internal/types"
"sim-server/app/main/model"
"sim-server/common/xerr"
"sim-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
})
}