2026-01-16 17:01:36 +08:00
|
|
|
|
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),但可以通过其他字段记录退款金额
|
2026-01-16 18:23:43 +08:00
|
|
|
|
if _, updateYunyinErr := l.svcCtx.YunyinSignPayOrderModel.Update(l.ctx, nil, yunyinOrder); updateYunyinErr != nil {
|
2026-01-16 17:01:36 +08:00
|
|
|
|
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
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|