v1.0
This commit is contained in:
@@ -7,11 +7,13 @@ import (
|
||||
"time"
|
||||
"ycc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/smartwalle/alipay/v3"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AlipayCallbackLogic struct {
|
||||
@@ -40,6 +42,9 @@ func (l *AlipayCallbackLogic) AlipayCallback(w http.ResponseWriter, r *http.Requ
|
||||
if strings.HasPrefix(orderNo, "Q_") {
|
||||
// 查询订单处理
|
||||
return l.handleQueryOrderPayment(w, notification)
|
||||
} else if strings.HasPrefix(orderNo, "U_") {
|
||||
// 代理升级订单处理
|
||||
return l.handleAgentUpgradeOrderPayment(w, notification)
|
||||
} else if strings.HasPrefix(orderNo, "A_") {
|
||||
// 旧系统会员充值订单(已废弃,新系统使用升级功能)
|
||||
// return l.handleAgentVipOrderPayment(w, notification)
|
||||
@@ -105,6 +110,104 @@ func (l *AlipayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter, not
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理代理升级订单支付
|
||||
func (l *AlipayCallbackLogic) handleAgentUpgradeOrderPayment(w http.ResponseWriter, notification *alipay.Notification) error {
|
||||
orderNo := notification.OutTradeNo
|
||||
|
||||
// 1. 查找订单
|
||||
order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, orderNo)
|
||||
if findOrderErr != nil {
|
||||
logx.Errorf("支付宝支付回调,查找升级订单失败: %+v", findOrderErr)
|
||||
alipay.ACKNotification(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 2. 验证金额
|
||||
amount := lzUtils.ToAlipayAmount(order.Amount)
|
||||
user, err := l.svcCtx.UserModel.FindOne(l.ctx, order.UserId)
|
||||
if err == nil && user.Inside != 1 {
|
||||
if amount != notification.TotalAmount {
|
||||
logx.Errorf("支付宝支付回调,升级订单金额不一致,订单号: %s", orderNo)
|
||||
alipay.ACKNotification(w)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 检查订单状态
|
||||
if order.Status != "pending" {
|
||||
alipay.ACKNotification(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 4. 查找升级记录
|
||||
upgradeRecords, findUpgradeErr := l.svcCtx.AgentUpgradeModel.FindAll(l.ctx, l.svcCtx.AgentUpgradeModel.SelectBuilder().
|
||||
Where("order_no = ?", orderNo).
|
||||
Limit(1), "")
|
||||
if findUpgradeErr != nil || len(upgradeRecords) == 0 {
|
||||
logx.Errorf("支付宝支付回调,查找升级记录失败,订单号: %s, 错误: %+v", orderNo, findUpgradeErr)
|
||||
alipay.ACKNotification(w)
|
||||
return nil
|
||||
}
|
||||
upgradeRecord := upgradeRecords[0]
|
||||
|
||||
// 5. 检查升级记录状态
|
||||
if upgradeRecord.Status != 1 {
|
||||
// 升级记录状态不是待支付,直接返回成功
|
||||
alipay.ACKNotification(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 6. 处理支付状态
|
||||
switch notification.TradeStatus {
|
||||
case alipay.TradeStatusSuccess:
|
||||
order.Status = "paid"
|
||||
order.PayTime = lzUtils.TimeToNullTime(time.Now())
|
||||
order.PlatformOrderId = lzUtils.StringToNullString(notification.TradeNo)
|
||||
case alipay.TradeStatusClosed:
|
||||
order.Status = "closed"
|
||||
order.CloseTime = lzUtils.TimeToNullTime(time.Now())
|
||||
default:
|
||||
alipay.ACKNotification(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 7. 更新订单状态
|
||||
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
|
||||
logx.Errorf("支付宝支付回调,更新升级订单状态失败: %+v", updateErr)
|
||||
alipay.ACKNotification(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 8. 如果支付成功,执行升级操作
|
||||
if order.Status == "paid" {
|
||||
err := l.svcCtx.AgentWalletModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 8.1 执行升级操作
|
||||
if err := l.svcCtx.AgentService.ProcessUpgrade(transCtx, upgradeRecord.AgentId, upgradeRecord.ToLevel, upgradeRecord.UpgradeType, upgradeRecord.UpgradeFee, upgradeRecord.RebateAmount, orderNo, 0); err != nil {
|
||||
return errors.Wrapf(err, "执行升级操作失败")
|
||||
}
|
||||
|
||||
// 8.2 更新升级记录状态为已完成
|
||||
upgradeRecord.Status = 2 // 已完成(status: 1=待处理,2=已完成,3=已失败)
|
||||
upgradeRecord.Remark = lzUtils.StringToNullString("支付成功,升级完成")
|
||||
if updateErr := l.svcCtx.AgentUpgradeModel.UpdateWithVersion(transCtx, session, upgradeRecord); updateErr != nil {
|
||||
return errors.Wrapf(updateErr, "更新升级记录状态失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logx.Errorf("支付宝支付回调,处理升级订单失败,订单号: %s, 错误: %+v", orderNo, err)
|
||||
// 即使升级失败,也返回成功给支付宝,避免重复回调
|
||||
} else {
|
||||
logx.Infof("支付宝支付回调,代理升级成功,订单号: %s, 代理ID: %d, 从等级 %d 升级到等级 %d", orderNo, upgradeRecord.AgentId, upgradeRecord.FromLevel, upgradeRecord.ToLevel)
|
||||
}
|
||||
}
|
||||
|
||||
alipay.ACKNotification(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理代理会员订单支付(已废弃,新系统使用升级功能)
|
||||
/*
|
||||
func (l *AlipayCallbackLogic) handleAgentVipOrderPayment(w http.ResponseWriter, notification *alipay.Notification) error {
|
||||
|
||||
@@ -2,6 +2,7 @@ package pay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
@@ -25,17 +26,18 @@ func NewPaymentCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Paym
|
||||
}
|
||||
|
||||
func (l *PaymentCheckLogic) PaymentCheck(req *types.PaymentCheckReq) (resp *types.PaymentCheckResp, err error) {
|
||||
// 旧系统会员充值订单(已废弃,新系统使用升级功能)
|
||||
// if strings.HasPrefix(req.OrderNo, "A_") {
|
||||
// order, err := l.svcCtx.AgentMembershipRechargeOrderModel.FindOneByOrderNo(l.ctx, req.OrderNo)
|
||||
// if err != nil {
|
||||
// return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询订单失败: %v", err)
|
||||
// }
|
||||
// return &types.PaymentCheckResp{
|
||||
// Type: "agent_vip",
|
||||
// Status: order.Status,
|
||||
// }, nil
|
||||
// }
|
||||
// 根据订单号前缀判断订单类型
|
||||
if strings.HasPrefix(req.OrderNo, "U_") {
|
||||
// 升级订单
|
||||
order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询升级订单失败: %v", err)
|
||||
}
|
||||
return &types.PaymentCheckResp{
|
||||
Type: "agent_upgrade",
|
||||
Status: order.Status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 查询订单(包括代理订单)
|
||||
order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo)
|
||||
|
||||
@@ -2,14 +2,19 @@ package pay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/redis/go-redis/v9"
|
||||
@@ -26,6 +31,7 @@ type PaymentTypeResp struct {
|
||||
amount float64
|
||||
outTradeNo string
|
||||
description string
|
||||
orderID int64 // 订单ID,用于开发环境测试支付模式
|
||||
}
|
||||
|
||||
func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLogic {
|
||||
@@ -39,6 +45,13 @@ func NewPaymentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PaymentLo
|
||||
func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp, err error) {
|
||||
var paymentTypeResp *PaymentTypeResp
|
||||
var prepayData interface{}
|
||||
var orderID int64
|
||||
|
||||
// 检查是否为开发环境的测试支付模式
|
||||
env := os.Getenv("ENV")
|
||||
isDevTestPayment := env == "development" && (req.PayMethod == "test" || req.PayMethod == "test_empty")
|
||||
isEmptyReportMode := env == "development" && req.PayMethod == "test_empty"
|
||||
|
||||
l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
switch req.PayType {
|
||||
case "agent_vip":
|
||||
@@ -52,8 +65,33 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case "agent_upgrade":
|
||||
paymentTypeResp, err = l.AgentUpgradeOrderPayment(req, session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 开发环境测试支付模式:跳过实际支付流程
|
||||
// 注意:订单状态更新在事务外进行,避免在事务中查询不到订单的问题
|
||||
if isDevTestPayment {
|
||||
// 获取订单ID(从 QueryOrderPayment 返回的 orderID)
|
||||
if paymentTypeResp.orderID <= 0 {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "开发测试模式,订单ID无效")
|
||||
}
|
||||
orderID = paymentTypeResp.orderID
|
||||
|
||||
// 在事务中只记录订单ID,不更新订单状态
|
||||
// 订单状态的更新和后续流程在事务提交后处理
|
||||
logx.Infof("开发环境测试支付模式:订单 %s (ID: %d) 将在事务提交后更新状态", paymentTypeResp.outTradeNo, orderID)
|
||||
|
||||
// 返回测试支付标识
|
||||
prepayData = "test_payment_success"
|
||||
return nil
|
||||
}
|
||||
|
||||
// 正常支付流程
|
||||
var createOrderErr error
|
||||
if req.PayMethod == "wechat" {
|
||||
prepayData, createOrderErr = l.svcCtx.WechatPayService.CreateWechatOrder(l.ctx, paymentTypeResp.amount, paymentTypeResp.description, paymentTypeResp.outTradeNo)
|
||||
@@ -70,6 +108,90 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 开发环境测试支付模式:事务提交后处理订单状态更新和后续流程
|
||||
if isDevTestPayment && paymentTypeResp != nil && paymentTypeResp.orderID > 0 {
|
||||
// 使用 goroutine 异步处理,确保事务已完全提交
|
||||
go func() {
|
||||
// 短暂延迟,确保事务已完全提交到数据库
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
finalOrderID := paymentTypeResp.orderID
|
||||
|
||||
// 查找订单并更新状态为已支付
|
||||
order, findOrderErr := l.svcCtx.OrderModel.FindOne(context.Background(), finalOrderID)
|
||||
if findOrderErr != nil {
|
||||
logx.Errorf("开发测试模式,查找订单失败,订单ID: %d, 错误: %v", finalOrderID, findOrderErr)
|
||||
return
|
||||
}
|
||||
|
||||
// 更新订单状态为已支付
|
||||
order.Status = "paid"
|
||||
now := time.Now()
|
||||
order.PayTime = sql.NullTime{Time: now, Valid: true}
|
||||
|
||||
// 空报告模式:在 PaymentPlatform 字段中标记,用于后续生成空报告
|
||||
if isEmptyReportMode {
|
||||
order.PaymentPlatform = "test_empty"
|
||||
logx.Infof("开发环境空报告模式:订单 %s (ID: %d) 已标记为空报告模式", paymentTypeResp.outTradeNo, finalOrderID)
|
||||
}
|
||||
|
||||
// 更新订单状态(在事务外执行)
|
||||
updateErr := l.svcCtx.OrderModel.UpdateWithVersion(context.Background(), nil, order)
|
||||
if updateErr != nil {
|
||||
logx.Errorf("开发测试模式,更新订单状态失败,订单ID: %d, 错误: %+v", finalOrderID, updateErr)
|
||||
return
|
||||
}
|
||||
|
||||
logx.Infof("开发环境测试支付模式:订单 %s (ID: %d) 已自动标记为已支付", paymentTypeResp.outTradeNo, finalOrderID)
|
||||
|
||||
// 再次短暂延迟,确保订单状态更新已提交
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
// 根据订单类型处理后续流程
|
||||
if strings.HasPrefix(paymentTypeResp.outTradeNo, "U_") {
|
||||
// 升级订单:直接执行升级操作
|
||||
upgradeRecords, findUpgradeErr := l.svcCtx.AgentUpgradeModel.FindAll(context.Background(), l.svcCtx.AgentUpgradeModel.SelectBuilder().
|
||||
Where("order_no = ?", paymentTypeResp.outTradeNo).
|
||||
Limit(1), "")
|
||||
if findUpgradeErr != nil || len(upgradeRecords) == 0 {
|
||||
logx.Errorf("开发测试模式,查找升级记录失败,订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, findUpgradeErr)
|
||||
return
|
||||
}
|
||||
upgradeRecord := upgradeRecords[0]
|
||||
|
||||
// 执行升级操作
|
||||
err := l.svcCtx.AgentWalletModel.Trans(context.Background(), func(transCtx context.Context, session sqlx.Session) error {
|
||||
if err := l.svcCtx.AgentService.ProcessUpgrade(transCtx, upgradeRecord.AgentId, upgradeRecord.ToLevel, upgradeRecord.UpgradeType, upgradeRecord.UpgradeFee, upgradeRecord.RebateAmount, paymentTypeResp.outTradeNo, 0); err != nil {
|
||||
return errors.Wrapf(err, "执行升级操作失败")
|
||||
}
|
||||
|
||||
// 更新升级记录状态为已完成
|
||||
upgradeRecord.Status = 2 // 已完成(status: 1=待处理,2=已完成,3=已失败)
|
||||
upgradeRecord.Remark = lzUtils.StringToNullString("测试支付成功,升级完成")
|
||||
if updateErr := l.svcCtx.AgentUpgradeModel.UpdateWithVersion(transCtx, session, upgradeRecord); updateErr != nil {
|
||||
return errors.Wrapf(updateErr, "更新升级记录状态失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logx.Errorf("开发测试模式,处理升级订单失败,订单号: %s, 错误: %+v", paymentTypeResp.outTradeNo, err)
|
||||
} else {
|
||||
logx.Infof("开发测试模式,代理升级成功,订单号: %s, 代理ID: %d", paymentTypeResp.outTradeNo, upgradeRecord.AgentId)
|
||||
}
|
||||
} else {
|
||||
// 查询订单:发送支付成功通知任务,触发后续流程(生成报告和代理处理)
|
||||
if sendErr := l.svcCtx.AsynqService.SendQueryTask(finalOrderID); sendErr != nil {
|
||||
logx.Errorf("开发测试模式,发送支付成功通知任务失败,订单ID: %d, 错误: %+v", finalOrderID, sendErr)
|
||||
} else {
|
||||
logx.Infof("开发测试模式,已发送支付成功通知任务,订单ID: %d", finalOrderID)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
switch v := prepayData.(type) {
|
||||
case string:
|
||||
// 如果 prepayData 是字符串类型,直接返回
|
||||
@@ -153,19 +275,35 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 查询代理信息失败: %+v", err)
|
||||
}
|
||||
|
||||
// 获取系统配置
|
||||
basePrice, err := l.getConfigFloat("base_price")
|
||||
// 获取产品配置(必须存在)
|
||||
productConfig, err := l.svcCtx.AgentProductConfigModel.FindOneByProductId(l.ctx, product.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取基础底价配置失败: %+v", err)
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单失败,产品配置不存在, productId: %d,请先在后台配置产品价格参数", product.Id)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 查询产品配置失败: %+v", err)
|
||||
}
|
||||
priceThreshold, _ := l.getConfigFloat("price_threshold")
|
||||
priceFeeRate, _ := l.getConfigFloat("price_fee_rate")
|
||||
|
||||
// 计算实际底价(基础底价+等级加成)
|
||||
levelBonus := l.getLevelBonus(agent.Level)
|
||||
// 获取等级加成(需要从系统配置读取)
|
||||
levelBonus, err := l.getLevelBonus(agent.Level)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 获取等级加成配置失败: %+v", err)
|
||||
}
|
||||
|
||||
// 使用产品配置的底价计算实际底价
|
||||
basePrice := productConfig.BasePrice
|
||||
actualBasePrice := basePrice + float64(levelBonus)
|
||||
|
||||
// 计算提价成本
|
||||
// 计算提价成本(使用产品配置)
|
||||
priceThreshold := 0.0
|
||||
priceFeeRate := 0.0
|
||||
if productConfig.PriceThreshold.Valid {
|
||||
priceThreshold = productConfig.PriceThreshold.Float64
|
||||
}
|
||||
if productConfig.PriceFeeRate.Valid {
|
||||
priceFeeRate = productConfig.PriceFeeRate.Float64
|
||||
}
|
||||
|
||||
priceCost := 0.0
|
||||
if agentLinkModel.SetPrice > priceThreshold {
|
||||
priceCost = (agentLinkModel.SetPrice - priceThreshold) * priceFeeRate
|
||||
@@ -191,25 +329,138 @@ func (l *PaymentLogic) QueryOrderPayment(req *types.PaymentReq, session sqlx.Ses
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成订单, 保存代理订单失败: %+v", agentOrderInsert)
|
||||
}
|
||||
}
|
||||
return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName}, nil
|
||||
return &PaymentTypeResp{amount: amount, outTradeNo: outTradeNo, description: product.ProductName, orderID: orderID}, nil
|
||||
}
|
||||
|
||||
// AgentVipOrderPayment 代理会员充值订单(已废弃,新系统使用升级功能替代)
|
||||
func (l *PaymentLogic) AgentVipOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) {
|
||||
// 新代理系统已废弃会员充值功能,请使用升级功能
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("该功能已废弃,请使用代理升级功能"), "")
|
||||
}
|
||||
// getLevelBonus 获取等级加成
|
||||
func (l *PaymentLogic) getLevelBonus(level int64) int64 {
|
||||
|
||||
// AgentUpgradeOrderPayment 代理升级订单支付
|
||||
func (l *PaymentLogic) AgentUpgradeOrderPayment(req *types.PaymentReq, session sqlx.Session) (resp *PaymentTypeResp, err error) {
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
|
||||
}
|
||||
|
||||
// 1. 解析升级记录ID
|
||||
upgradeId, err := strconv.ParseInt(req.Id, 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "无效的升级记录ID: %s", req.Id)
|
||||
}
|
||||
|
||||
// 2. 查找升级记录
|
||||
upgradeRecord, err := l.svcCtx.AgentUpgradeModel.FindOne(l.ctx, upgradeId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("升级记录不存在"), "")
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询升级记录失败, %v", err)
|
||||
}
|
||||
|
||||
// 3. 验证升级记录状态(必须是待支付状态)
|
||||
if upgradeRecord.Status != 1 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("升级记录状态不正确,无法支付"), "")
|
||||
}
|
||||
|
||||
// 4. 验证代理ID是否匹配
|
||||
agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
|
||||
}
|
||||
if agent.Id != upgradeRecord.AgentId {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("无权支付此升级订单"), "")
|
||||
}
|
||||
|
||||
// 5. 生成订单号(使用 U_ 前缀表示升级订单)
|
||||
outTradeNo := fmt.Sprintf("U_%d_%d", upgradeId, time.Now().Unix())
|
||||
|
||||
// 6. 获取用户信息(用于内部用户判断)
|
||||
user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取用户信息失败: %v", err)
|
||||
}
|
||||
|
||||
// 7. 计算支付金额
|
||||
amount := upgradeRecord.UpgradeFee
|
||||
if user.Inside == 1 {
|
||||
amount = 0.01 // 内部用户测试金额
|
||||
}
|
||||
|
||||
// 8. 创建订单记录
|
||||
order := model.Order{
|
||||
OrderNo: outTradeNo,
|
||||
UserId: userID,
|
||||
ProductId: 0, // 升级订单没有产品ID
|
||||
PaymentPlatform: req.PayMethod,
|
||||
PaymentScene: "app",
|
||||
Amount: amount,
|
||||
Status: "pending",
|
||||
}
|
||||
orderInsertResult, insertOrderErr := l.svcCtx.OrderModel.Insert(l.ctx, session, &order)
|
||||
if insertOrderErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建订单失败: %+v", insertOrderErr)
|
||||
}
|
||||
orderID, lastInsertIdErr := orderInsertResult.LastInsertId()
|
||||
if lastInsertIdErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取订单ID失败: %+v", lastInsertIdErr)
|
||||
}
|
||||
|
||||
// 9. 更新升级记录的订单号
|
||||
upgradeRecord.OrderNo = lzUtils.StringToNullString(outTradeNo)
|
||||
if updateErr := l.svcCtx.AgentUpgradeModel.UpdateWithVersion(l.ctx, session, upgradeRecord); updateErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新升级记录订单号失败: %+v", updateErr)
|
||||
}
|
||||
|
||||
// 10. 生成描述信息
|
||||
levelNames := map[int64]string{
|
||||
1: "普通代理",
|
||||
2: "黄金代理",
|
||||
3: "钻石代理",
|
||||
}
|
||||
fromLevelName := levelNames[upgradeRecord.FromLevel]
|
||||
toLevelName := levelNames[upgradeRecord.ToLevel]
|
||||
description := fmt.Sprintf("代理升级:%s → %s", fromLevelName, toLevelName)
|
||||
|
||||
return &PaymentTypeResp{
|
||||
amount: amount,
|
||||
outTradeNo: outTradeNo,
|
||||
description: description,
|
||||
orderID: orderID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getLevelBonus 获取等级加成(从配置表读取)
|
||||
func (l *PaymentLogic) getLevelBonus(level int64) (int64, error) {
|
||||
var configKey string
|
||||
switch level {
|
||||
case 1: // 普通
|
||||
return 6
|
||||
configKey = "level_1_bonus"
|
||||
case 2: // 黄金
|
||||
return 3
|
||||
configKey = "level_2_bonus"
|
||||
case 3: // 钻石
|
||||
return 0
|
||||
configKey = "level_3_bonus"
|
||||
default:
|
||||
return 0
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
bonus, err := l.getConfigFloat(configKey)
|
||||
if err != nil {
|
||||
// 配置不存在时返回默认值
|
||||
l.Errorf("获取等级加成配置失败, level: %d, key: %s, err: %v,使用默认值", level, configKey, err)
|
||||
switch level {
|
||||
case 1:
|
||||
return 6, nil
|
||||
case 2:
|
||||
return 3, nil
|
||||
case 3:
|
||||
return 0, nil
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
return int64(bonus), nil
|
||||
}
|
||||
|
||||
// getConfigFloat 获取配置值(浮点数)
|
||||
|
||||
@@ -10,8 +10,10 @@ import (
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type WechatPayCallbackLogic struct {
|
||||
@@ -40,6 +42,9 @@ func (l *WechatPayCallbackLogic) WechatPayCallback(w http.ResponseWriter, r *htt
|
||||
if strings.HasPrefix(orderNo, "Q_") {
|
||||
// 查询订单处理
|
||||
return l.handleQueryOrderPayment(w, notification)
|
||||
} else if strings.HasPrefix(orderNo, "U_") {
|
||||
// 代理升级订单处理
|
||||
return l.handleAgentUpgradeOrderPayment(w, notification)
|
||||
} else if strings.HasPrefix(orderNo, "A_") {
|
||||
// 旧系统会员充值订单(已废弃,新系统使用升级功能)
|
||||
// return l.handleAgentVipOrderPayment(w, notification)
|
||||
@@ -104,6 +109,101 @@ func (l *WechatPayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter,
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理代理升级订单支付
|
||||
func (l *WechatPayCallbackLogic) handleAgentUpgradeOrderPayment(w http.ResponseWriter, notification *payments.Transaction) error {
|
||||
orderNo := *notification.OutTradeNo
|
||||
|
||||
// 1. 查找订单
|
||||
order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, orderNo)
|
||||
if findOrderErr != nil {
|
||||
logx.Errorf("微信支付回调,查找升级订单失败: %+v", findOrderErr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 2. 验证金额
|
||||
amount := lzUtils.ToWechatAmount(order.Amount)
|
||||
if amount != *notification.Amount.Total {
|
||||
logx.Errorf("微信支付回调,升级订单金额不一致,订单号: %s", orderNo)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 3. 检查订单状态
|
||||
if order.Status != "pending" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("success"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 4. 查找升级记录
|
||||
upgradeRecords, findUpgradeErr := l.svcCtx.AgentUpgradeModel.FindAll(l.ctx, l.svcCtx.AgentUpgradeModel.SelectBuilder().
|
||||
Where("order_no = ?", orderNo).
|
||||
Limit(1), "")
|
||||
if findUpgradeErr != nil || len(upgradeRecords) == 0 {
|
||||
logx.Errorf("微信支付回调,查找升级记录失败,订单号: %s, 错误: %+v", orderNo, findUpgradeErr)
|
||||
return nil
|
||||
}
|
||||
upgradeRecord := upgradeRecords[0]
|
||||
|
||||
// 5. 检查升级记录状态
|
||||
if upgradeRecord.Status != 1 {
|
||||
// 升级记录状态不是待支付,直接返回成功
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("success"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 6. 处理支付状态
|
||||
switch *notification.TradeState {
|
||||
case service.TradeStateSuccess:
|
||||
order.Status = "paid"
|
||||
order.PayTime = lzUtils.TimeToNullTime(time.Now())
|
||||
order.PlatformOrderId = lzUtils.StringToNullString(*notification.TransactionId)
|
||||
case service.TradeStateClosed:
|
||||
order.Status = "closed"
|
||||
order.CloseTime = lzUtils.TimeToNullTime(time.Now())
|
||||
case service.TradeStateRevoked:
|
||||
order.Status = "failed"
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// 7. 更新订单状态
|
||||
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
|
||||
logx.Errorf("微信支付回调,更新升级订单状态失败: %+v", updateErr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 8. 如果支付成功,执行升级操作
|
||||
if order.Status == "paid" {
|
||||
err := l.svcCtx.AgentWalletModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 8.1 执行升级操作
|
||||
if err := l.svcCtx.AgentService.ProcessUpgrade(transCtx, upgradeRecord.AgentId, upgradeRecord.ToLevel, upgradeRecord.UpgradeType, upgradeRecord.UpgradeFee, upgradeRecord.RebateAmount, orderNo, 0); err != nil {
|
||||
return errors.Wrapf(err, "执行升级操作失败")
|
||||
}
|
||||
|
||||
// 8.2 更新升级记录状态为已完成
|
||||
upgradeRecord.Status = 2 // 已完成(status: 1=待处理,2=已完成,3=已失败)
|
||||
upgradeRecord.Remark = lzUtils.StringToNullString("支付成功,升级完成")
|
||||
if updateErr := l.svcCtx.AgentUpgradeModel.UpdateWithVersion(transCtx, session, upgradeRecord); updateErr != nil {
|
||||
return errors.Wrapf(updateErr, "更新升级记录状态失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logx.Errorf("微信支付回调,处理升级订单失败,订单号: %s, 错误: %+v", orderNo, err)
|
||||
// 即使升级失败,也返回成功给微信,避免重复回调
|
||||
} else {
|
||||
logx.Infof("微信支付回调,代理升级成功,订单号: %s, 代理ID: %d, 从等级 %d 升级到等级 %d", orderNo, upgradeRecord.AgentId, upgradeRecord.FromLevel, upgradeRecord.ToLevel)
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("success"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// 处理代理会员订单支付(已废弃,新系统使用升级功能)
|
||||
/*
|
||||
func (l *WechatPayCallbackLogic) handleAgentVipOrderPayment(w http.ResponseWriter, notification *payments.Transaction) error {
|
||||
|
||||
Reference in New Issue
Block a user