fix
This commit is contained in:
@@ -47,6 +47,36 @@ func (l *AdminGetOrderDetailLogic) AdminGetOrderDetail(req *types.AdminGetOrderD
|
||||
isPromotion = 1
|
||||
}
|
||||
|
||||
// 判断是否为代理订单并获取代理处理状态
|
||||
var isAgentOrder bool
|
||||
var agentProcessStatus string
|
||||
|
||||
agentOrder, err := l.svcCtx.AgentOrderModel.FindOneByOrderId(l.ctx, order.Id)
|
||||
if err == nil && agentOrder != nil {
|
||||
isAgentOrder = true
|
||||
|
||||
// 查询代理佣金记录
|
||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentCommissionModel.SelectBuilder().Where("order_id = ?", order.Id), "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderDetail, 查询代理佣金失败 err: %v", err)
|
||||
}
|
||||
|
||||
if len(commissions) > 0 {
|
||||
agentProcessStatus = "success"
|
||||
} else {
|
||||
// 检查订单状态,如果是已支付但无佣金记录,则为待处理或失败
|
||||
if order.Status == "paid" {
|
||||
agentProcessStatus = "pending"
|
||||
} else {
|
||||
agentProcessStatus = "failed"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isAgentOrder = false
|
||||
agentProcessStatus = "not_agent"
|
||||
}
|
||||
|
||||
// 获取查询状态
|
||||
var queryState string
|
||||
builder := l.svcCtx.QueryModel.SelectBuilder().Where("order_id = ?", order.Id).Columns("query_state")
|
||||
@@ -78,18 +108,20 @@ func (l *AdminGetOrderDetailLogic) AdminGetOrderDetail(req *types.AdminGetOrderD
|
||||
|
||||
// 构建响应
|
||||
resp = &types.AdminGetOrderDetailResp{
|
||||
Id: order.Id,
|
||||
OrderNo: order.OrderNo,
|
||||
PlatformOrderId: order.PlatformOrderId.String,
|
||||
ProductName: product.ProductName,
|
||||
PaymentPlatform: order.PaymentPlatform,
|
||||
PaymentScene: order.PaymentScene,
|
||||
Amount: order.Amount,
|
||||
Status: order.Status,
|
||||
CreateTime: order.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: order.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
IsPromotion: isPromotion,
|
||||
QueryState: queryState,
|
||||
Id: order.Id,
|
||||
OrderNo: order.OrderNo,
|
||||
PlatformOrderId: order.PlatformOrderId.String,
|
||||
ProductName: product.ProductName,
|
||||
PaymentPlatform: order.PaymentPlatform,
|
||||
PaymentScene: order.PaymentScene,
|
||||
Amount: order.Amount,
|
||||
Status: order.Status,
|
||||
CreateTime: order.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: order.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
IsPromotion: isPromotion,
|
||||
QueryState: queryState,
|
||||
IsAgentOrder: isAgentOrder,
|
||||
AgentProcessStatus: agentProcessStatus,
|
||||
}
|
||||
|
||||
// 处理可选字段
|
||||
|
||||
@@ -102,6 +102,9 @@ func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListR
|
||||
// 并发获取产品信息和查询状态
|
||||
productMap := make(map[int64]string)
|
||||
queryStateMap := make(map[int64]string)
|
||||
agentOrderMap := make(map[int64]bool) // 代理订单映射
|
||||
agentProcessStatusMap := make(map[int64]string) // 代理处理状态映射
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
// 批量获取查询状态
|
||||
@@ -160,6 +163,60 @@ func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 批量获取代理订单状态
|
||||
agentOrders, err := l.svcCtx.AgentOrderModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentOrderModel.SelectBuilder().Where(squirrel.Eq{"order_id": orderIds}), "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 批量查询代理订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 记录代理订单
|
||||
for _, agentOrder := range agentOrders {
|
||||
agentOrderMap[agentOrder.OrderId] = true
|
||||
}
|
||||
|
||||
// 对于代理订单,查询代理处理状态
|
||||
if len(agentOrders) > 0 {
|
||||
agentOrderIds := make([]int64, 0, len(agentOrders))
|
||||
for _, agentOrder := range agentOrders {
|
||||
agentOrderIds = append(agentOrderIds, agentOrder.OrderId)
|
||||
}
|
||||
|
||||
// 查询代理佣金记录
|
||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentCommissionModel.SelectBuilder().Where(squirrel.Eq{"order_id": agentOrderIds}), "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 批量查询代理佣金失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 记录有佣金记录的订单为处理成功
|
||||
processedOrderIds := make(map[int64]bool)
|
||||
for _, commission := range commissions {
|
||||
processedOrderIds[commission.OrderId] = true
|
||||
}
|
||||
|
||||
// 创建订单状态映射,避免重复查找
|
||||
orderStatusMap := make(map[int64]string)
|
||||
for _, order := range orders {
|
||||
orderStatusMap[order.Id] = order.Status
|
||||
}
|
||||
|
||||
// 设置代理处理状态
|
||||
for _, agentOrder := range agentOrders {
|
||||
orderId := agentOrder.OrderId
|
||||
if processedOrderIds[orderId] {
|
||||
agentProcessStatusMap[orderId] = "success"
|
||||
} else {
|
||||
// 检查订单状态,如果是已支付但无佣金记录,则为待处理或失败
|
||||
if orderStatusMap[orderId] == "paid" {
|
||||
agentProcessStatusMap[orderId] = "pending"
|
||||
} else {
|
||||
agentProcessStatusMap[orderId] = "failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 并发获取产品信息
|
||||
@@ -222,6 +279,15 @@ func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListR
|
||||
if err == nil && promotionOrder != nil {
|
||||
item.IsPromotion = 1
|
||||
}
|
||||
|
||||
// 设置代理订单相关字段
|
||||
if agentOrderMap[order.Id] {
|
||||
item.IsAgentOrder = true
|
||||
item.AgentProcessStatus = agentProcessStatusMap[order.Id]
|
||||
} else {
|
||||
item.IsAgentOrder = false
|
||||
item.AgentProcessStatus = "not_agent"
|
||||
}
|
||||
resp.Items = append(resp.Items, item)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,13 @@ import (
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
const (
|
||||
PaymentPlatformAlipay = "alipay"
|
||||
PaymentPlatformWechat = "wechat"
|
||||
OrderStatusPaid = "paid"
|
||||
RefundNoPrefix = "refund-"
|
||||
)
|
||||
|
||||
type AdminRefundOrderLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
@@ -29,64 +36,158 @@ func NewAdminRefundOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminRefundOrderLogic) AdminRefundOrder(req *types.AdminRefundOrderReq) (resp *types.AdminRefundOrderResp, err error) {
|
||||
// 获取订单信息
|
||||
order, err := l.svcCtx.OrderModel.FindOne(l.ctx, req.Id)
|
||||
// 获取并验证订单
|
||||
order, err := l.getAndValidateOrder(req.Id, req.RefundAmount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 根据支付平台处理退款
|
||||
switch order.PaymentPlatform {
|
||||
case PaymentPlatformAlipay:
|
||||
return l.handleAlipayRefund(order, req)
|
||||
case PaymentPlatformWechat:
|
||||
return l.handleWechatRefund(order, req)
|
||||
default:
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("不支持的支付平台"), "AdminRefundOrder, 不支持的支付平台: %s", order.PaymentPlatform)
|
||||
}
|
||||
}
|
||||
|
||||
// getAndValidateOrder 获取并验证订单信息
|
||||
func (l *AdminRefundOrderLogic) getAndValidateOrder(orderId int64, refundAmount float64) (*model.Order, error) {
|
||||
order, err := l.svcCtx.OrderModel.FindOne(l.ctx, orderId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminRefundOrder, 查询订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 检查订单状态
|
||||
if order.Status != "paid" {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("订单状态不正确,无法退款"), "AdminRefundOrder, 订单状态不正确,无法退款 err: %v", err)
|
||||
if order.Status != OrderStatusPaid {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("订单状态不正确,无法退款"), "AdminRefundOrder, 订单状态: %s", order.Status)
|
||||
}
|
||||
|
||||
// 检查退款金额
|
||||
if req.RefundAmount > order.Amount {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("退款金额不能大于订单金额"), "AdminRefundOrder, 退款金额不能大于订单金额 err: %v", err)
|
||||
if refundAmount > order.Amount {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("退款金额不能大于订单金额"), "AdminRefundOrder, 退款金额: %f, 订单金额: %f", refundAmount, order.Amount)
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
// handleAlipayRefund 处理支付宝退款
|
||||
func (l *AdminRefundOrderLogic) handleAlipayRefund(order *model.Order, req *types.AdminRefundOrderReq) (*types.AdminRefundOrderResp, error) {
|
||||
// 调用支付宝退款接口
|
||||
refundResp, err := l.svcCtx.AlipayService.AliRefund(l.ctx, order.OrderNo, req.RefundAmount)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 退款失败 err: %v", err)
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 支付宝退款失败 err: %v", err)
|
||||
}
|
||||
|
||||
refundNo := l.generateRefundNo(order.OrderNo)
|
||||
|
||||
if refundResp.IsSuccess() {
|
||||
err = l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 创建退款记录
|
||||
refund := &model.OrderRefund{
|
||||
RefundNo: fmt.Sprintf("refund-%s", order.OrderNo),
|
||||
PlatformRefundId: sql.NullString{String: refundResp.TradeNo, Valid: true},
|
||||
OrderId: order.Id,
|
||||
UserId: order.UserId,
|
||||
ProductId: order.ProductId,
|
||||
RefundAmount: req.RefundAmount,
|
||||
RefundReason: sql.NullString{String: req.RefundReason, Valid: true},
|
||||
Status: model.OrderRefundStatusPending,
|
||||
RefundTime: sql.NullTime{Time: time.Now(), Valid: true},
|
||||
}
|
||||
|
||||
if _, err := l.svcCtx.OrderRefundModel.Insert(ctx, session, refund); err != nil {
|
||||
return fmt.Errorf("创建退款记录失败: %v", err)
|
||||
}
|
||||
|
||||
// 更新订单状态
|
||||
order.Status = model.OrderStatusRefunded
|
||||
order.RefundTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||
if _, err := l.svcCtx.OrderModel.Update(ctx, session, order); err != nil {
|
||||
return fmt.Errorf("更新订单状态失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
// 支付宝退款成功,创建成功记录
|
||||
err = l.createRefundRecordAndUpdateOrder(order, req, refundNo, refundResp.TradeNo, model.OrderStatusRefunded, model.OrderRefundStatusSuccess)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 退款失败 err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminRefundOrderResp{
|
||||
Status: model.OrderStatusRefunded,
|
||||
RefundNo: fmt.Sprintf("refund-%s", order.OrderNo),
|
||||
RefundNo: refundNo,
|
||||
Amount: req.RefundAmount,
|
||||
}, nil
|
||||
} else {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("退款失败, : %v", refundResp.Msg)), "AdminRefundOrder, 退款失败 err: %v", err)
|
||||
// 支付宝退款失败,创建失败记录但不更新订单状态
|
||||
err = l.createRefundRecordOnly(order, req, refundNo, refundResp.TradeNo, model.OrderRefundStatusFailed)
|
||||
if err != nil {
|
||||
logx.Errorf("创建退款失败记录时出错: %v", err)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("退款失败: %v", refundResp.Msg)), "AdminRefundOrder, 支付宝退款失败")
|
||||
}
|
||||
}
|
||||
|
||||
// handleWechatRefund 处理微信退款
|
||||
func (l *AdminRefundOrderLogic) handleWechatRefund(order *model.Order, req *types.AdminRefundOrderReq) (*types.AdminRefundOrderResp, error) {
|
||||
// 调用微信退款接口
|
||||
err := l.svcCtx.WechatPayService.WeChatRefund(l.ctx, order.OrderNo, req.RefundAmount, order.Amount)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 微信退款失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 微信退款是异步的,创建pending状态的退款记录
|
||||
refundNo := l.generateRefundNo(order.OrderNo)
|
||||
err = l.createRefundRecordAndUpdateOrder(order, req, refundNo, "", model.OrderStatusRefunding, model.OrderRefundStatusPending)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminRefundOrderResp{
|
||||
Status: model.OrderRefundStatusPending,
|
||||
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 {
|
||||
// 创建退款记录
|
||||
refund := &model.OrderRefund{
|
||||
RefundNo: refundNo,
|
||||
PlatformRefundId: l.createNullString(platformRefundId),
|
||||
OrderId: order.Id,
|
||||
UserId: order.UserId,
|
||||
ProductId: order.ProductId,
|
||||
RefundAmount: req.RefundAmount,
|
||||
RefundReason: l.createNullString(req.RefundReason),
|
||||
Status: refundStatus, // 使用传入的状态,不再硬编码
|
||||
RefundTime: sql.NullTime{Time: time.Now(), Valid: true},
|
||||
}
|
||||
|
||||
if _, err := l.svcCtx.OrderRefundModel.Insert(ctx, session, refund); err != nil {
|
||||
return fmt.Errorf("创建退款记录失败: %v", err)
|
||||
}
|
||||
|
||||
// 更新订单状态
|
||||
order.Status = orderStatus
|
||||
if _, err := l.svcCtx.OrderModel.Update(ctx, session, order); err != nil {
|
||||
return fmt.Errorf("更新订单状态失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// createRefundRecordOnly 仅创建退款记录,不更新订单状态(用于退款失败的情况)
|
||||
func (l *AdminRefundOrderLogic) createRefundRecordOnly(order *model.Order, req *types.AdminRefundOrderReq, refundNo, platformRefundId, refundStatus string) error {
|
||||
refund := &model.OrderRefund{
|
||||
RefundNo: refundNo,
|
||||
PlatformRefundId: l.createNullString(platformRefundId),
|
||||
OrderId: order.Id,
|
||||
UserId: order.UserId,
|
||||
ProductId: order.ProductId,
|
||||
RefundAmount: req.RefundAmount,
|
||||
RefundReason: l.createNullString(req.RefundReason),
|
||||
Status: refundStatus,
|
||||
RefundTime: sql.NullTime{Time: time.Now(), Valid: true},
|
||||
}
|
||||
|
||||
_, err := l.svcCtx.OrderRefundModel.Insert(l.ctx, nil, refund)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建退款记录失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateRefundNo 生成退款单号
|
||||
func (l *AdminRefundOrderLogic) generateRefundNo(orderNo string) string {
|
||||
return fmt.Sprintf("%s%s", RefundNoPrefix, orderNo)
|
||||
}
|
||||
|
||||
// createNullString 创建 sql.NullString
|
||||
func (l *AdminRefundOrderLogic) createNullString(value string) sql.NullString {
|
||||
return sql.NullString{
|
||||
String: value,
|
||||
Valid: value != "",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package admin_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"tydata-server/app/main/api/internal/svc"
|
||||
"tydata-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminRetryAgentProcessLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminRetryAgentProcessLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminRetryAgentProcessLogic {
|
||||
return &AdminRetryAgentProcessLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminRetryAgentProcessLogic) AdminRetryAgentProcess(req *types.AdminRetryAgentProcessReq) (resp *types.AdminRetryAgentProcessResp, err error) {
|
||||
// 调用AgentService的重新执行代理处理方法
|
||||
err = l.svcCtx.AgentService.RetryAgentProcess(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
// 检查是否是"已经处理"的错误
|
||||
if err.Error() == "代理处理已经成功,无需重新执行" {
|
||||
return &types.AdminRetryAgentProcessResp{
|
||||
Status: "already_processed",
|
||||
Message: "代理处理已经成功,无需重新执行",
|
||||
ProcessedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 其他错误
|
||||
logx.Errorf("重新执行代理处理失败,订单ID: %d, 错误: %v", req.Id, err)
|
||||
return &types.AdminRetryAgentProcessResp{
|
||||
Status: "failed",
|
||||
Message: err.Error(),
|
||||
ProcessedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 执行成功
|
||||
return &types.AdminRetryAgentProcessResp{
|
||||
Status: "success",
|
||||
Message: "代理处理重新执行成功",
|
||||
ProcessedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
@@ -353,6 +353,15 @@ func (l *AgentWithdrawalLogic) updateWithdrawalStatus(outBizNo string, status in
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新扣税记录失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 提现成功后,给上级代理发放提现奖励
|
||||
withdrawRewardErr := l.svcCtx.AgentService.GiveWithdrawReward(ctx, record.AgentId, record.Amount, session)
|
||||
if withdrawRewardErr != nil {
|
||||
l.Logger.Errorf("发放提现奖励失败,代理ID:%d,提现金额:%f,错误:%+v", record.AgentId, record.Amount, withdrawRewardErr)
|
||||
// 提现奖励失败不影响主流程,只记录日志
|
||||
} else {
|
||||
l.Logger.Infof("发放提现奖励成功,代理ID:%d,提现金额:%f", record.AgentId, record.Amount)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -4,13 +4,16 @@ import (
|
||||
"context"
|
||||
"tydata-server/common/xerr"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"tydata-server/app/main/api/internal/svc"
|
||||
"tydata-server/app/main/api/internal/types"
|
||||
"tydata-server/app/main/model"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type GetLinkDataLogic struct {
|
||||
@@ -37,9 +40,46 @@ func (l *GetLinkDataLogic) GetLinkData(req *types.GetLinkDataReq) (resp *types.G
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理链接数据, %v", err)
|
||||
}
|
||||
|
||||
// 查询产品关联的 feature
|
||||
build := l.svcCtx.ProductFeatureModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"product_id": productModel.Id,
|
||||
})
|
||||
productFeatureAll, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, build, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理链接数据, 查找产品关联错误: %v", err)
|
||||
}
|
||||
|
||||
var product types.Product
|
||||
copier.Copy(&product, productModel)
|
||||
err = copier.Copy(&product, productModel)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理链接数据, 产品信息结构体复制失败, %v", err)
|
||||
}
|
||||
product.SellPrice = agentLinkModel.Price
|
||||
|
||||
// 并发查询所有 feature 详情
|
||||
mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for _, productFeature := range productFeatureAll {
|
||||
source <- productFeature.FeatureId
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[*model.Feature], cancel func(error)) {
|
||||
id := item.(int64)
|
||||
|
||||
feature, findFeatureErr := l.svcCtx.FeatureModel.FindOne(l.ctx, id)
|
||||
if findFeatureErr != nil {
|
||||
logx.WithContext(l.ctx).Errorf("获取代理链接数据, 查找关联feature错误: %d, err:%v", id, findFeatureErr)
|
||||
return
|
||||
}
|
||||
if feature != nil && feature.Id > 0 {
|
||||
writer.Write(feature)
|
||||
}
|
||||
}, func(pipe <-chan *model.Feature, cancel func(error)) {
|
||||
for item := range pipe {
|
||||
var feature types.Feature
|
||||
_ = copier.Copy(&feature, item)
|
||||
product.Features = append(product.Features, feature)
|
||||
}
|
||||
})
|
||||
return &types.GetLinkDataResp{
|
||||
Product: product,
|
||||
}, nil
|
||||
|
||||
100
app/main/api/internal/logic/agent/getmembershipinfologic.go
Normal file
100
app/main/api/internal/logic/agent/getmembershipinfologic.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"tydata-server/app/main/api/internal/svc"
|
||||
"tydata-server/app/main/api/internal/types"
|
||||
"tydata-server/app/main/model"
|
||||
"tydata-server/common/xerr"
|
||||
"tydata-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetMembershipInfoLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetMembershipInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMembershipInfoLogic {
|
||||
return &GetMembershipInfoLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetMembershipInfoLogic) GetMembershipInfo() (resp *types.GetMembershipInfoResp, err error) {
|
||||
// 获取普通代理配置
|
||||
normalConfig, err := l.svcCtx.AgentMembershipConfigModel.FindOneByLevelName(l.ctx, model.AgentLeveNameNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取普通代理配置失败: %v", err)
|
||||
}
|
||||
|
||||
// 获取VIP会员配置
|
||||
vipConfig, err := l.svcCtx.AgentMembershipConfigModel.FindOneByLevelName(l.ctx, model.AgentLeveNameVIP)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取VIP会员配置失败: %v", err)
|
||||
}
|
||||
|
||||
// 获取SVIP会员配置
|
||||
svipConfig, err := l.svcCtx.AgentMembershipConfigModel.FindOneByLevelName(l.ctx, model.AgentLeveNameSVIP)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取SVIP会员配置失败: %v", err)
|
||||
}
|
||||
|
||||
// 转换配置的辅助函数
|
||||
convertConfig := func(config *model.AgentMembershipConfig) (types.MembershipConfigInfo, error) {
|
||||
var configInfo types.MembershipConfigInfo
|
||||
err := copier.Copy(&configInfo, config)
|
||||
if err != nil {
|
||||
return configInfo, err
|
||||
}
|
||||
// 转换Null类型字段
|
||||
configInfo.Price = lzUtils.NullFloat64ToFloat64(config.Price)
|
||||
configInfo.ReportCommission = lzUtils.NullFloat64ToFloat64(config.ReportCommission)
|
||||
configInfo.LowerActivityReward = lzUtils.NullFloat64ToFloat64(config.LowerActivityReward)
|
||||
configInfo.NewActivityReward = lzUtils.NullFloat64ToFloat64(config.NewActivityReward)
|
||||
configInfo.LowerStandardCount = lzUtils.NullInt64ToInt64(config.LowerStandardCount)
|
||||
configInfo.NewLowerStandardCount = lzUtils.NullInt64ToInt64(config.NewLowerStandardCount)
|
||||
configInfo.LowerWithdrawRewardRatio = lzUtils.NullFloat64ToFloat64(config.LowerWithdrawRewardRatio)
|
||||
configInfo.LowerConvertVipReward = lzUtils.NullFloat64ToFloat64(config.LowerConvertVipReward)
|
||||
configInfo.LowerConvertSvipReward = lzUtils.NullFloat64ToFloat64(config.LowerConvertSvipReward)
|
||||
configInfo.ExemptionAmount = lzUtils.NullFloat64ToFloat64(config.ExemptionAmount)
|
||||
configInfo.PriceIncreaseMax = lzUtils.NullFloat64ToFloat64(config.PriceIncreaseMax)
|
||||
configInfo.PriceRatio = lzUtils.NullFloat64ToFloat64(config.PriceRatio)
|
||||
configInfo.PriceIncreaseAmount = lzUtils.NullFloat64ToFloat64(config.PriceIncreaseAmount)
|
||||
return configInfo, nil
|
||||
}
|
||||
|
||||
// 转换普通代理配置
|
||||
normalConfigInfo, err := convertConfig(normalConfig)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "转换普通代理配置失败: %v", err)
|
||||
}
|
||||
|
||||
// 转换VIP配置
|
||||
vipConfigInfo, err := convertConfig(vipConfig)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "转换VIP配置失败: %v", err)
|
||||
}
|
||||
|
||||
// 转换SVIP配置
|
||||
svipConfigInfo, err := convertConfig(svipConfig)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "转换SVIP配置失败: %v", err)
|
||||
}
|
||||
|
||||
// 构建响应数据
|
||||
resp = &types.GetMembershipInfoResp{
|
||||
NormalConfig: normalConfigInfo,
|
||||
VipConfig: vipConfigInfo,
|
||||
SvipConfig: svipConfigInfo,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -2,11 +2,11 @@ package pay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"tydata-server/pkg/lzkit/lzUtils"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"tydata-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/smartwalle/alipay/v3"
|
||||
|
||||
@@ -151,22 +151,40 @@ func (l *AlipayCallbackLogic) handleAgentVipOrderPayment(w http.ResponseWriter,
|
||||
return fmt.Errorf("修改代理会员订单信息失败: %+v", updateErr)
|
||||
}
|
||||
|
||||
// 记录旧等级,用于判断是否为升级
|
||||
oldLevel := agentModel.LevelName
|
||||
|
||||
// 设置会员等级
|
||||
agentModel.LevelName = agentOrder.LevelName
|
||||
|
||||
// 延长会员时间
|
||||
// 检查是否是同级续费并记录到日志
|
||||
isRenewal := agentModel.LevelName == agentOrder.LevelName && agentModel.MembershipExpiryTime.Valid
|
||||
if isRenewal {
|
||||
logx.Infof("代理会员续费成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName)
|
||||
// 检查是否是有效期内续费(不发放奖励)还是重新激活(发放奖励)
|
||||
isValidRenewal := oldLevel == agentOrder.LevelName && agentModel.MembershipExpiryTime.Valid && agentModel.MembershipExpiryTime.Time.After(time.Now())
|
||||
if isValidRenewal {
|
||||
logx.Infof("代理会员有效期内续费成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName)
|
||||
} else {
|
||||
logx.Infof("代理会员新购或升级成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName)
|
||||
logx.Infof("代理会员新购、升级或重新激活成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName)
|
||||
}
|
||||
agentModel.MembershipExpiryTime = lzUtils.RenewMembership(agentModel.MembershipExpiryTime)
|
||||
|
||||
if updateErr := l.svcCtx.AgentModel.UpdateWithVersion(l.ctx, nil, agentModel); updateErr != nil {
|
||||
return fmt.Errorf("修改代理信息失败: %+v", updateErr)
|
||||
}
|
||||
|
||||
// 如果不是有效期内续费,给上级代理发放升级奖励
|
||||
if !isValidRenewal && (agentOrder.LevelName == model.AgentLeveNameVIP || agentOrder.LevelName == model.AgentLeveNameSVIP) {
|
||||
// 验证升级路径的有效性
|
||||
if oldLevel != agentOrder.LevelName {
|
||||
upgradeRewardErr := l.svcCtx.AgentService.GiveUpgradeReward(transCtx, agentModel.Id, oldLevel, agentOrder.LevelName, session)
|
||||
if upgradeRewardErr != nil {
|
||||
logx.Errorf("发放升级奖励失败,代理ID:%d,旧等级:%s,新等级:%s,错误:%+v", agentModel.Id, oldLevel, agentOrder.LevelName, upgradeRewardErr)
|
||||
// 升级奖励失败不影响主流程,只记录日志
|
||||
} else {
|
||||
logx.Infof("发放升级奖励成功,代理ID:%d,旧等级:%s,新等级:%s", agentModel.Id, oldLevel, agentOrder.LevelName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -188,7 +188,18 @@ func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 获取代理会员配置失败, %+v", err)
|
||||
}
|
||||
|
||||
// 验证会员配置价格是否有效
|
||||
if !agentMembershipConfig.Price.Valid {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 会员等级%s的价格配置无效", agentVipCache.Type)
|
||||
}
|
||||
|
||||
amount := agentMembershipConfig.Price.Float64
|
||||
// 验证价格是否合理
|
||||
if amount <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成订单, 会员等级%s的价格配置无效: %f", agentVipCache.Type, amount)
|
||||
}
|
||||
|
||||
// 内部用户测试金额
|
||||
if user.Inside == 1 {
|
||||
amount = 0.01
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@ package pay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"tydata-server/app/main/api/internal/service"
|
||||
"tydata-server/app/main/model"
|
||||
"tydata-server/pkg/lzkit/lzUtils"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"tydata-server/app/main/api/internal/service"
|
||||
"tydata-server/app/main/model"
|
||||
"tydata-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"tydata-server/app/main/api/internal/svc"
|
||||
|
||||
@@ -150,21 +150,40 @@ func (l *WechatPayCallbackLogic) handleAgentVipOrderPayment(w http.ResponseWrite
|
||||
return fmt.Errorf("修改代理会员订单信息失败: %+v", updateErr)
|
||||
}
|
||||
|
||||
// 记录旧等级,用于判断是否为升级
|
||||
oldLevel := agentModel.LevelName
|
||||
|
||||
// 设置会员等级
|
||||
agentModel.LevelName = agentOrder.LevelName
|
||||
|
||||
// 延长会员时间
|
||||
isRenewal := agentModel.LevelName == agentOrder.LevelName && agentModel.MembershipExpiryTime.Valid
|
||||
if isRenewal {
|
||||
logx.Infof("代理会员续费成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName)
|
||||
// 检查是否是有效期内续费(不发放奖励)还是重新激活(发放奖励)
|
||||
isValidRenewal := oldLevel == agentOrder.LevelName && agentModel.MembershipExpiryTime.Valid && agentModel.MembershipExpiryTime.Time.After(time.Now())
|
||||
if isValidRenewal {
|
||||
logx.Infof("代理会员有效期内续费成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName)
|
||||
} else {
|
||||
logx.Infof("代理会员新购或升级成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName)
|
||||
logx.Infof("代理会员新购、升级或重新激活成功,会员ID:%d,等级:%s", agentModel.Id, agentModel.LevelName)
|
||||
}
|
||||
agentModel.MembershipExpiryTime = lzUtils.RenewMembership(agentModel.MembershipExpiryTime)
|
||||
|
||||
if updateErr := l.svcCtx.AgentModel.UpdateWithVersion(l.ctx, nil, agentModel); updateErr != nil {
|
||||
return fmt.Errorf("修改代理信息失败: %+v", updateErr)
|
||||
}
|
||||
|
||||
// 如果不是有效期内续费,给上级代理发放升级奖励
|
||||
if !isValidRenewal && (agentOrder.LevelName == model.AgentLeveNameVIP || agentOrder.LevelName == model.AgentLeveNameSVIP) {
|
||||
// 验证升级路径的有效性
|
||||
if oldLevel != agentOrder.LevelName {
|
||||
upgradeRewardErr := l.svcCtx.AgentService.GiveUpgradeReward(transCtx, agentModel.Id, oldLevel, agentOrder.LevelName, session)
|
||||
if upgradeRewardErr != nil {
|
||||
logx.Errorf("发放升级奖励失败,代理ID:%d,旧等级:%s,新等级:%s,错误:%+v", agentModel.Id, oldLevel, agentOrder.LevelName, upgradeRewardErr)
|
||||
// 升级奖励失败不影响主流程,只记录日志
|
||||
} else {
|
||||
logx.Infof("发放升级奖励成功,代理ID:%d,旧等级:%s,新等级:%s", agentModel.Id, oldLevel, agentOrder.LevelName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
|
||||
@@ -2,11 +2,18 @@ package pay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"tydata-server/app/main/api/internal/svc"
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"tydata-server/app/main/api/internal/svc"
|
||||
"tydata-server/app/main/model"
|
||||
"tydata-server/common/globalkey"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type WechatPayRefundCallbackLogic struct {
|
||||
@@ -23,33 +30,207 @@ func NewWechatPayRefundCallbackLogic(ctx context.Context, svcCtx *svc.ServiceCon
|
||||
}
|
||||
}
|
||||
|
||||
func (l *WechatPayRefundCallbackLogic) WechatPayRefundCallback(w http.ResponseWriter, r *http.Request) error {
|
||||
notification, err := l.svcCtx.WechatPayService.HandleRefundNotification(l.ctx, r)
|
||||
// handleQueryOrderRefund 处理查询订单退款
|
||||
func (l *WechatPayRefundCallbackLogic) handleQueryOrderRefund(orderNo string, status refunddomestic.Status) error {
|
||||
order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, orderNo)
|
||||
if err != nil {
|
||||
logx.Errorf("微信退款回调,%v", err)
|
||||
return nil
|
||||
return errors.Wrapf(err, "查找查询订单信息失败: %s", orderNo)
|
||||
}
|
||||
order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, *notification.OutTradeNo)
|
||||
if findOrderErr != nil {
|
||||
logx.Errorf("微信退款回调,查找订单信息失败: %+v", findOrderErr)
|
||||
|
||||
// 检查订单是否已经处理过退款
|
||||
if order.Status == model.OrderStatusRefunded {
|
||||
logx.Infof("订单已经是退款状态,无需重复处理: orderNo=%s", orderNo)
|
||||
return nil
|
||||
}
|
||||
|
||||
switch *notification.Status {
|
||||
// 只处理成功和失败状态
|
||||
var orderStatus, refundStatus string
|
||||
switch status {
|
||||
case refunddomestic.STATUS_SUCCESS:
|
||||
order.Status = "refunded"
|
||||
orderStatus = model.OrderStatusRefunded
|
||||
refundStatus = model.OrderRefundStatusSuccess
|
||||
case refunddomestic.STATUS_CLOSED:
|
||||
// 退款关闭,保持订单原状态,更新退款记录为失败
|
||||
refundStatus = model.OrderRefundStatusFailed
|
||||
case refunddomestic.STATUS_ABNORMAL:
|
||||
// 异常
|
||||
return nil
|
||||
// 退款异常,保持订单原状态,更新退款记录为失败
|
||||
refundStatus = model.OrderRefundStatusFailed
|
||||
default:
|
||||
// 其他状态暂不处理
|
||||
return nil
|
||||
}
|
||||
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
|
||||
logx.Errorf("微信退款回调,更新订单失败%+v", updateErr)
|
||||
|
||||
// 使用事务同时更新订单和退款记录
|
||||
err = l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 更新订单状态(仅在退款成功时更新)
|
||||
if status == refunddomestic.STATUS_SUCCESS {
|
||||
order.Status = orderStatus
|
||||
order.RefundTime = sql.NullTime{
|
||||
Time: time.Now(),
|
||||
Valid: true,
|
||||
}
|
||||
if err := l.svcCtx.OrderModel.UpdateWithVersion(ctx, session, order); err != nil {
|
||||
return errors.Wrapf(err, "更新查询订单状态失败: %s", orderNo)
|
||||
}
|
||||
}
|
||||
|
||||
// 查找最新的pending状态的退款记录
|
||||
refund, err := l.findLatestPendingRefund(ctx, order.Id)
|
||||
if err != nil {
|
||||
if err == model.ErrNotFound {
|
||||
logx.Errorf("未找到订单对应的待处理退款记录: orderNo=%s, orderId=%d", orderNo, order.Id)
|
||||
return nil // 没有退款记录时不报错,只记录警告
|
||||
}
|
||||
return errors.Wrapf(err, "查找退款记录失败: orderNo=%s", orderNo)
|
||||
}
|
||||
|
||||
// 检查退款记录是否已经处理过
|
||||
if refund.Status == model.OrderRefundStatusSuccess {
|
||||
logx.Infof("退款记录已经是成功状态,无需重复处理: orderNo=%s, refundId=%d", orderNo, refund.Id)
|
||||
return nil
|
||||
}
|
||||
|
||||
refund.Status = refundStatus
|
||||
if status == refunddomestic.STATUS_SUCCESS {
|
||||
refund.RefundTime = sql.NullTime{
|
||||
Time: time.Now(),
|
||||
Valid: true,
|
||||
}
|
||||
} else if status == refunddomestic.STATUS_CLOSED {
|
||||
refund.CloseTime = sql.NullTime{
|
||||
Time: time.Now(),
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := l.svcCtx.OrderRefundModel.Update(ctx, session, refund); err != nil {
|
||||
return errors.Wrapf(err, "更新退款记录状态失败: orderNo=%s", orderNo)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "更新订单和退款记录失败: %s", orderNo)
|
||||
}
|
||||
// 响应微信回调成功
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("success")) // 确保只写入一次响应
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleAgentOrderRefund 处理代理会员订单退款
|
||||
func (l *WechatPayRefundCallbackLogic) handleAgentOrderRefund(orderNo string, status refunddomestic.Status) error {
|
||||
order, err := l.svcCtx.AgentMembershipRechargeOrderModel.FindOneByOrderNo(l.ctx, orderNo)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查找代理会员订单信息失败: %s", orderNo)
|
||||
}
|
||||
|
||||
// 检查订单是否已经处理过退款
|
||||
if order.Status == "refunded" {
|
||||
logx.Infof("代理会员订单已经是退款状态,无需重复处理: orderNo=%s", orderNo)
|
||||
return nil
|
||||
}
|
||||
|
||||
if status == refunddomestic.STATUS_SUCCESS {
|
||||
order.Status = "refunded"
|
||||
} else if status == refunddomestic.STATUS_ABNORMAL {
|
||||
return nil // 异常状态直接返回
|
||||
} else {
|
||||
return nil // 其他状态直接返回
|
||||
}
|
||||
|
||||
if err := l.svcCtx.AgentMembershipRechargeOrderModel.UpdateWithVersion(l.ctx, nil, order); err != nil {
|
||||
return errors.Wrapf(err, "更新代理会员订单状态失败: %s", orderNo)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendSuccessResponse 发送成功响应
|
||||
func (l *WechatPayRefundCallbackLogic) sendSuccessResponse(w http.ResponseWriter) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("success"))
|
||||
}
|
||||
|
||||
func (l *WechatPayRefundCallbackLogic) WechatPayRefundCallback(w http.ResponseWriter, r *http.Request) error {
|
||||
// 1. 处理微信退款通知
|
||||
notification, err := l.svcCtx.WechatPayService.HandleRefundNotification(l.ctx, r)
|
||||
if err != nil {
|
||||
logx.Errorf("微信退款回调处理失败: %v", err)
|
||||
l.sendSuccessResponse(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 2. 检查关键字段是否为空
|
||||
if notification.OutTradeNo == nil {
|
||||
logx.Errorf("微信退款回调OutTradeNo字段为空")
|
||||
l.sendSuccessResponse(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
orderNo := *notification.OutTradeNo
|
||||
|
||||
// 3. 判断退款状态,优先使用Status,如果Status为nil则使用SuccessTime判断
|
||||
var status refunddomestic.Status
|
||||
var statusDetermined bool = false
|
||||
|
||||
if notification.Status != nil {
|
||||
status = *notification.Status
|
||||
statusDetermined = true
|
||||
} else if notification.SuccessTime != nil && !notification.SuccessTime.IsZero() {
|
||||
// 如果Status为空但SuccessTime有值,说明退款成功
|
||||
status = refunddomestic.STATUS_SUCCESS
|
||||
statusDetermined = true
|
||||
} else {
|
||||
logx.Errorf("微信退款回调Status和SuccessTime都为空,无法确定退款状态: orderNo=%s", orderNo)
|
||||
l.sendSuccessResponse(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !statusDetermined {
|
||||
logx.Errorf("微信退款回调无法确定退款状态: orderNo=%s", orderNo)
|
||||
l.sendSuccessResponse(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
var processErr error
|
||||
|
||||
// 4. 根据订单号前缀处理不同类型的订单
|
||||
switch {
|
||||
case strings.HasPrefix(orderNo, "Q_"):
|
||||
processErr = l.handleQueryOrderRefund(orderNo, status)
|
||||
case strings.HasPrefix(orderNo, "A_"):
|
||||
processErr = l.handleAgentOrderRefund(orderNo, status)
|
||||
default:
|
||||
// 兼容旧订单,假设没有前缀的是查询订单
|
||||
processErr = l.handleQueryOrderRefund(orderNo, status)
|
||||
}
|
||||
|
||||
// 5. 处理错误并响应
|
||||
if processErr != nil {
|
||||
logx.Errorf("处理退款订单失败: orderNo=%s, err=%v", orderNo, processErr)
|
||||
}
|
||||
|
||||
// 无论处理是否成功,都返回成功响应给微信
|
||||
l.sendSuccessResponse(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// findLatestPendingRefund 查找订单最新的pending状态退款记录
|
||||
func (l *WechatPayRefundCallbackLogic) findLatestPendingRefund(ctx context.Context, orderId int64) (*model.OrderRefund, error) {
|
||||
// 使用SelectBuilder查询最新的pending状态退款记录
|
||||
builder := l.svcCtx.OrderRefundModel.SelectBuilder().
|
||||
Where("order_id = ? AND status = ? AND del_state = ?", orderId, model.OrderRefundStatusPending, globalkey.DelStateNo).
|
||||
OrderBy("id DESC").
|
||||
Limit(1)
|
||||
|
||||
refunds, err := l.svcCtx.OrderRefundModel.FindAll(ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(refunds) == 0 {
|
||||
return nil, model.ErrNotFound
|
||||
}
|
||||
|
||||
return refunds[0], nil
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@ package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"tydata-server/common/ctxdata"
|
||||
"tydata-server/common/xerr"
|
||||
"tydata-server/pkg/lzkit/crypto"
|
||||
"tydata-server/pkg/lzkit/lzUtils"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"tydata-server/common/ctxdata"
|
||||
"tydata-server/common/xerr"
|
||||
"tydata-server/pkg/lzkit/crypto"
|
||||
"tydata-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
@@ -104,6 +104,7 @@ func (l *QueryDetailByOrderIdLogic) QueryDetailByOrderId(req *types.QueryDetailB
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %v", err)
|
||||
}
|
||||
query.ProductName = product.ProductName
|
||||
query.Product = product.ProductEn
|
||||
return &types.QueryDetailByOrderIdResp{
|
||||
Query: query,
|
||||
}, nil
|
||||
|
||||
@@ -2,10 +2,10 @@ package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"tydata-server/common/ctxdata"
|
||||
"tydata-server/common/xerr"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"tydata-server/common/ctxdata"
|
||||
"tydata-server/common/xerr"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
@@ -94,6 +94,7 @@ func (l *QueryDetailByOrderNoLogic) QueryDetailByOrderNo(req *types.QueryDetailB
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %v", err)
|
||||
}
|
||||
query.Product = product.ProductEn
|
||||
query.ProductName = product.ProductName
|
||||
return &types.QueryDetailByOrderNoResp{
|
||||
Query: query,
|
||||
|
||||
@@ -37,6 +37,7 @@ func (l *QueryExampleLogic) QueryExample(req *types.QueryExampleReq) (resp *type
|
||||
|
||||
// 创建一个空的Query结构体来存储结果
|
||||
query := types.Query{
|
||||
Product: product.ProductEn,
|
||||
ProductName: product.ProductName,
|
||||
QueryData: make([]types.QueryItem, 0),
|
||||
QueryParams: make(map[string]interface{}),
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"tydata-server/app/main/api/internal/svc"
|
||||
"tydata-server/app/main/api/internal/types"
|
||||
"tydata-server/app/main/model"
|
||||
"tydata-server/common/ctxdata"
|
||||
"tydata-server/common/xerr"
|
||||
|
||||
@@ -58,7 +59,14 @@ func (l *QueryListLogic) QueryList(req *types.QueryListReq) (resp *types.QueryLi
|
||||
if findProductErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告列表查询, 获取商品信息失败, %+v", err)
|
||||
}
|
||||
|
||||
// 检查订单状态,如果订单已退款,则设置查询状态为已退款
|
||||
order, findOrderErr := l.svcCtx.OrderModel.FindOne(l.ctx, queryModel.OrderId)
|
||||
if findOrderErr == nil && order.Status == model.OrderStatusRefunded {
|
||||
query.QueryState = model.QueryStateRefunded
|
||||
}
|
||||
query.ProductName = product.ProductName
|
||||
query.Product = product.ProductEn
|
||||
list = append(list, query)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ func (l *QueryShareDetailLogic) QueryShareDetail(req *types.QueryShareDetailReq)
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %v", err)
|
||||
}
|
||||
query.ProductName = product.ProductName
|
||||
query.Product = product.ProductEn
|
||||
return &types.QueryShareDetailResp{
|
||||
Status: "success",
|
||||
Query: query,
|
||||
|
||||
Reference in New Issue
Block a user