package recharge import ( "context" "fmt" "testing" "time" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/model/dto" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/tests/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "gorm.io/gorm" ) // setupTestService 创建测试用的 Service 实例 func setupTestService(t *testing.T) (*Service, *gorm.DB) { t.Helper() tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) logger, _ := zap.NewDevelopment() // 创建各个 Store rechargeStore := postgres.NewRechargeStore(tx, rdb) walletStore := postgres.NewWalletStore(tx, rdb) walletTransactionStore := postgres.NewWalletTransactionStore(tx, rdb) iotCardStore := postgres.NewIotCardStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) shopSeriesAllocationStore := postgres.NewShopSeriesAllocationStore(tx) commissionRecordStore := postgres.NewCommissionRecordStore(tx, rdb) service := New( tx, rechargeStore, walletStore, walletTransactionStore, iotCardStore, deviceStore, shopSeriesAllocationStore, commissionRecordStore, logger, ) return service, tx } // createTestIotCard 创建测试用 IoT 卡 func createTestIotCard(t *testing.T, tx *gorm.DB, shopID *uint, seriesAllocationID *uint) *model.IotCard { t.Helper() timestamp := time.Now().UnixNano() card := &model.IotCard{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ICCID: fmt.Sprintf("89860%014d", timestamp%100000000000000), CardType: "流量卡", CardCategory: "normal", CarrierID: 1, CarrierType: "CMCC", CarrierName: "中国移动", Status: 1, ShopID: shopID, SeriesAllocationID: seriesAllocationID, } require.NoError(t, tx.Create(card).Error) return card } // createTestDevice 创建测试用设备 func createTestDevice(t *testing.T, tx *gorm.DB, shopID *uint, seriesAllocationID *uint) *model.Device { t.Helper() timestamp := time.Now().UnixNano() device := &model.Device{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, DeviceNo: fmt.Sprintf("DEV%014d", timestamp%100000000000000), DeviceName: "测试设备", DeviceType: "GPS", Status: 1, ShopID: shopID, SeriesAllocationID: seriesAllocationID, } require.NoError(t, tx.Create(device).Error) return device } // createTestWallet 创建测试用钱包 func createTestWallet(t *testing.T, tx *gorm.DB, resourceType string, resourceID uint, walletType string) *model.Wallet { t.Helper() wallet := &model.Wallet{ ResourceType: resourceType, ResourceID: resourceID, WalletType: walletType, Balance: 0, Currency: "CNY", Status: 1, Version: 0, } require.NoError(t, tx.Create(wallet).Error) return wallet } // createTestShop 创建测试用店铺 func createTestShop(t *testing.T, tx *gorm.DB) *model.Shop { t.Helper() timestamp := time.Now().UnixNano() shop := &model.Shop{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ShopName: fmt.Sprintf("测试店铺%d", timestamp%10000), ShopCode: fmt.Sprintf("SHOP%d", timestamp%1000000), Level: 1, ContactName: "测试联系人", ContactPhone: fmt.Sprintf("138%08d", timestamp%100000000), Status: 1, } require.NoError(t, tx.Create(shop).Error) return shop } // createTestSeriesAllocation 创建测试用系列分配 func createTestSeriesAllocation(t *testing.T, tx *gorm.DB, shopID uint, enableOneTime bool, trigger string, threshold int64, enableForceRecharge bool, forceAmount int64) *model.ShopSeriesAllocation { t.Helper() allocation := &model.ShopSeriesAllocation{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ShopID: shopID, SeriesID: 1, AllocatorShopID: 0, BaseCommissionMode: "percent", BaseCommissionValue: 100, EnableOneTimeCommission: enableOneTime, OneTimeCommissionType: "fixed", OneTimeCommissionTrigger: trigger, OneTimeCommissionThreshold: threshold, OneTimeCommissionMode: "fixed", OneTimeCommissionValue: 5000, // 50元佣金 EnableForceRecharge: enableForceRecharge, ForceRechargeAmount: forceAmount, Status: 1, } require.NoError(t, tx.Create(allocation).Error) return allocation } // TestService_Create 测试创建充值订单 func TestService_Create(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("成功创建充值订单_iot_card", func(t *testing.T) { // 准备测试数据 card := createTestIotCard(t, tx, nil, nil) createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建充值订单 req := &dto.CreateRechargeRequest{ ResourceType: "iot_card", ResourceID: card.ID, Amount: 10000, // 100元 PaymentMethod: "wechat", } resp, err := service.Create(ctx, req, 1) require.NoError(t, err) assert.NotNil(t, resp) assert.Equal(t, int64(10000), resp.Amount) assert.Equal(t, "wechat", resp.PaymentMethod) assert.Equal(t, constants.RechargeStatusPending, resp.Status) assert.True(t, len(resp.RechargeNo) > 0) assert.Contains(t, resp.RechargeNo, "RCH") }) t.Run("成功创建充值订单_device", func(t *testing.T) { // 准备测试数据 device := createTestDevice(t, tx, nil, nil) createTestWallet(t, tx, "device", device.ID, "main") // 创建充值订单 req := &dto.CreateRechargeRequest{ ResourceType: "device", ResourceID: device.ID, Amount: 5000, // 50元 PaymentMethod: "alipay", } resp, err := service.Create(ctx, req, 1) require.NoError(t, err) assert.NotNil(t, resp) assert.Equal(t, int64(5000), resp.Amount) assert.Equal(t, "alipay", resp.PaymentMethod) }) t.Run("金额低于最小值", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) createTestWallet(t, tx, "iot_card", card.ID, "main") req := &dto.CreateRechargeRequest{ ResourceType: "iot_card", ResourceID: card.ID, Amount: 50, // 0.5元,低于1元 PaymentMethod: "wechat", } resp, err := service.Create(ctx, req, 1) assert.Error(t, err) assert.Nil(t, resp) assert.Contains(t, err.Error(), "充值金额不能低于1元") }) t.Run("金额超过最大值", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) createTestWallet(t, tx, "iot_card", card.ID, "main") req := &dto.CreateRechargeRequest{ ResourceType: "iot_card", ResourceID: card.ID, Amount: 20000000, // 200000元,超过100000元 PaymentMethod: "wechat", } resp, err := service.Create(ctx, req, 1) assert.Error(t, err) assert.Nil(t, resp) assert.Contains(t, err.Error(), "充值金额不能超过100000元") }) t.Run("无效的资源类型", func(t *testing.T) { req := &dto.CreateRechargeRequest{ ResourceType: "invalid", ResourceID: 1, Amount: 10000, PaymentMethod: "wechat", } resp, err := service.Create(ctx, req, 1) assert.Error(t, err) assert.Nil(t, resp) assert.Contains(t, err.Error(), "无效的资源类型") }) t.Run("钱包不存在", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) // 不创建钱包 req := &dto.CreateRechargeRequest{ ResourceType: "iot_card", ResourceID: card.ID, Amount: 10000, PaymentMethod: "wechat", } resp, err := service.Create(ctx, req, 1) assert.Error(t, err) assert.Nil(t, resp) assert.Contains(t, err.Error(), "钱包不存在") }) t.Run("强充金额不匹配_单次充值", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 10000, false, 0) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) createTestWallet(t, tx, "iot_card", card.ID, "main") req := &dto.CreateRechargeRequest{ ResourceType: "iot_card", ResourceID: card.ID, Amount: 5000, // 50元,但需要100元 PaymentMethod: "wechat", } resp, err := service.Create(ctx, req, 1) assert.Error(t, err) assert.Nil(t, resp) assert.Contains(t, err.Error(), "强充要求") }) t.Run("强充金额匹配成功_单次充值", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 10000, false, 0) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) createTestWallet(t, tx, "iot_card", card.ID, "main") req := &dto.CreateRechargeRequest{ ResourceType: "iot_card", ResourceID: card.ID, Amount: 10000, // 100元,符合要求 PaymentMethod: "wechat", } resp, err := service.Create(ctx, req, 1) require.NoError(t, err) assert.NotNil(t, resp) assert.Equal(t, int64(10000), resp.Amount) }) } // TestService_GetRechargeCheck 测试充值预检 func TestService_GetRechargeCheck(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("无强充要求_无系列分配", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) result, err := service.GetRechargeCheck(ctx, "iot_card", card.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) assert.Equal(t, int64(constants.RechargeMinAmount), result.MinAmount) assert.Equal(t, int64(constants.RechargeMaxAmount), result.MaxAmount) }) t.Run("需要强充_单次充值触发", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 10000, false, 0) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) result, err := service.GetRechargeCheck(ctx, "iot_card", card.ID) require.NoError(t, err) assert.True(t, result.NeedForceRecharge) assert.Equal(t, int64(10000), result.ForceRechargeAmount) assert.Equal(t, "single_recharge", result.TriggerType) }) t.Run("需要强充_累计充值启用强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "accumulated_recharge", 50000, true, 10000) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) result, err := service.GetRechargeCheck(ctx, "iot_card", card.ID) require.NoError(t, err) assert.True(t, result.NeedForceRecharge) assert.Equal(t, int64(10000), result.ForceRechargeAmount) // 使用配置的强充金额 assert.Equal(t, "accumulated_recharge", result.TriggerType) }) t.Run("无强充要求_累计充值未启用强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "accumulated_recharge", 50000, false, 0) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) result, err := service.GetRechargeCheck(ctx, "iot_card", card.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) assert.Contains(t, result.Message, "可自由充值") }) t.Run("无效的资源类型", func(t *testing.T) { result, err := service.GetRechargeCheck(ctx, "invalid", 1) assert.Error(t, err) assert.Nil(t, result) assert.Contains(t, err.Error(), "无效的资源类型") }) t.Run("资源不存在", func(t *testing.T) { result, err := service.GetRechargeCheck(ctx, "iot_card", 999999) assert.Error(t, err) assert.Nil(t, result) }) } // TestService_GetByID 测试根据ID查询充值订单 func TestService_GetByID(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("成功查询", func(t *testing.T) { // 准备测试数据 card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建充值订单 timestamp := time.Now().UnixNano() recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: fmt.Sprintf("RCH%d", timestamp), Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 查询 resp, err := service.GetByID(ctx, recharge.ID, 1) require.NoError(t, err) assert.NotNil(t, resp) assert.Equal(t, recharge.ID, resp.ID) assert.Equal(t, int64(10000), resp.Amount) }) t.Run("订单不存在", func(t *testing.T) { resp, err := service.GetByID(ctx, 999999, 1) assert.Error(t, err) assert.Nil(t, resp) assert.Contains(t, err.Error(), "充值订单不存在") }) t.Run("无权查看他人订单", func(t *testing.T) { // 准备测试数据 card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建用户1的订单 timestamp := time.Now().UnixNano() recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: fmt.Sprintf("RCH%d", timestamp), Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 用户2尝试查询 resp, err := service.GetByID(ctx, recharge.ID, 2) assert.Error(t, err) assert.Nil(t, resp) assert.Contains(t, err.Error(), "无权查看") }) } // TestService_List 测试查询充值订单列表 func TestService_List(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("查询用户订单列表", func(t *testing.T) { // 准备测试数据 card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建多个订单 for i := 0; i < 3; i++ { timestamp := time.Now().UnixNano() recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 100, Updater: 100, }, UserID: 100, WalletID: wallet.ID, RechargeNo: fmt.Sprintf("RCH%d%d", timestamp, i), Amount: int64((i + 1) * 1000), PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) } // 查询 req := &dto.RechargeListRequest{ Page: 1, PageSize: 10, } resp, err := service.List(ctx, req, 100) require.NoError(t, err) assert.NotNil(t, resp) assert.Equal(t, int64(3), resp.Total) assert.Len(t, resp.List, 3) }) t.Run("状态筛选", func(t *testing.T) { // 准备测试数据 card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建不同状态的订单 for i, status := range []int{constants.RechargeStatusPending, constants.RechargeStatusPaid, constants.RechargeStatusCompleted} { timestamp := time.Now().UnixNano() recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 101, Updater: 101, }, UserID: 101, WalletID: wallet.ID, RechargeNo: fmt.Sprintf("RCH%d%d", timestamp, i), Amount: 10000, PaymentMethod: "wechat", Status: status, } require.NoError(t, tx.Create(recharge).Error) } // 筛选待支付 pendingStatus := constants.RechargeStatusPending req := &dto.RechargeListRequest{ Page: 1, PageSize: 10, Status: &pendingStatus, } resp, err := service.List(ctx, req, 101) require.NoError(t, err) assert.NotNil(t, resp) assert.Equal(t, int64(1), resp.Total) }) } // TestService_HandlePaymentCallback 测试支付回调处理 func TestService_HandlePaymentCallback(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("成功处理支付回调_无佣金", func(t *testing.T) { // 准备测试数据 card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建待支付订单 rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 处理回调 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) // 验证订单状态 var updatedRecharge model.RechargeRecord err = tx.First(&updatedRecharge, recharge.ID).Error require.NoError(t, err) assert.Equal(t, constants.RechargeStatusCompleted, updatedRecharge.Status) // 验证钱包余额 var updatedWallet model.Wallet err = tx.First(&updatedWallet, wallet.ID).Error require.NoError(t, err) assert.Equal(t, int64(10000), updatedWallet.Balance) }) t.Run("幂等性_已支付订单重复回调", func(t *testing.T) { // 准备测试数据 card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") wallet.Balance = 10000 tx.Save(wallet) // 创建已完成订单 rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusCompleted, } require.NoError(t, tx.Create(recharge).Error) // 重复处理回调 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) // 应该成功(幂等) // 验证钱包余额没有变化 var updatedWallet model.Wallet err = tx.First(&updatedWallet, wallet.ID).Error require.NoError(t, err) assert.Equal(t, int64(10000), updatedWallet.Balance) // 余额不变 }) t.Run("订单不存在", func(t *testing.T) { err := service.HandlePaymentCallback(ctx, "RCH_NOT_EXISTS", "wechat", "TX123456") assert.Error(t, err) assert.Contains(t, err.Error(), "充值订单不存在") }) t.Run("订单状态不允许支付", func(t *testing.T) { // 准备测试数据 card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建已关闭订单 rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusClosed, } require.NoError(t, tx.Create(recharge).Error) // 处理回调 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") assert.Error(t, err) assert.Contains(t, err.Error(), "订单状态不允许支付") }) t.Run("成功处理支付回调_触发一次性佣金", func(t *testing.T) { // 准备测试数据 shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 10000, false, 0) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") createTestWallet(t, tx, "shop", shop.ID, "commission") // 店铺佣金钱包 // 创建待支付订单 rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, // 符合阈值 PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 处理回调 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) // 验证卡的 FirstCommissionPaid 已更新 var updatedCard model.IotCard err = tx.First(&updatedCard, card.ID).Error require.NoError(t, err) assert.True(t, updatedCard.FirstCommissionPaid) // 验证累计充值已更新 assert.Equal(t, int64(10000), updatedCard.AccumulatedRecharge) // 验证佣金记录已创建 var commissionRecords []model.CommissionRecord err = tx.Where("iot_card_id = ?", card.ID).Find(&commissionRecords).Error require.NoError(t, err) assert.Len(t, commissionRecords, 1) assert.Equal(t, int64(5000), commissionRecords[0].Amount) // 50元佣金 // 验证店铺佣金钱包余额 var shopWallet model.Wallet err = tx.Where("resource_type = ? AND resource_id = ? AND wallet_type = ?", "shop", shop.ID, "commission").First(&shopWallet).Error require.NoError(t, err) assert.Equal(t, int64(5000), shopWallet.Balance) }) t.Run("累计充值触发佣金", func(t *testing.T) { // 准备测试数据 shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "accumulated_recharge", 15000, false, 0) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) // 设置初始累计充值 card.AccumulatedRecharge = 10000 tx.Save(card) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") createTestWallet(t, tx, "shop", shop.ID, "commission") // 创建待支付订单 rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 5000, // 再充50元,累计150元,达到阈值 PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 处理回调 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) // 验证累计充值已更新 var updatedCard model.IotCard err = tx.First(&updatedCard, card.ID).Error require.NoError(t, err) assert.Equal(t, int64(15000), updatedCard.AccumulatedRecharge) assert.True(t, updatedCard.FirstCommissionPaid) }) } // TestService_generateRechargeNo 测试生成充值订单号 func TestService_generateRechargeNo(t *testing.T) { service, _ := setupTestService(t) t.Run("订单号格式正确", func(t *testing.T) { rechargeNo := service.generateRechargeNo() assert.True(t, len(rechargeNo) > 0) assert.Contains(t, rechargeNo, "RCH") // RCH + 14位时间戳 + 6位随机数 = 23位 assert.Equal(t, 23, len(rechargeNo)) }) t.Run("订单号唯一性", func(t *testing.T) { nos := make(map[string]bool) for i := 0; i < 100; i++ { no := service.generateRechargeNo() assert.False(t, nos[no], "订单号应唯一: %s", no) nos[no] = true } }) } // TestService_checkForceRechargeRequirement 测试强充验证逻辑 func TestService_checkForceRechargeRequirement(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("一次性佣金已发放_无需强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 10000, false, 0) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) // 标记佣金已发放 card.FirstCommissionPaid = true tx.Save(card) result, err := service.checkForceRechargeRequirement(ctx, "iot_card", card.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) assert.True(t, result.FirstCommissionPaid) }) t.Run("一次性佣金未启用_无需强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, false, "", 0, false, 0) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) result, err := service.checkForceRechargeRequirement(ctx, "iot_card", card.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) }) t.Run("设备资源类型", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 10000, false, 0) device := createTestDevice(t, tx, &shop.ID, &allocation.ID) result, err := service.checkForceRechargeRequirement(ctx, "device", device.ID) require.NoError(t, err) assert.True(t, result.NeedForceRecharge) assert.Equal(t, int64(10000), result.ForceRechargeAmount) }) } // TestService_calculateOneTimeCommission 测试计算一次性佣金 func TestService_calculateOneTimeCommission(t *testing.T) { service, _ := setupTestService(t) t.Run("固定金额佣金", func(t *testing.T) { allocation := &model.ShopSeriesAllocation{ OneTimeCommissionType: "fixed", OneTimeCommissionMode: "fixed", OneTimeCommissionValue: 5000, // 50元 } amount := service.calculateOneTimeCommission(allocation, 10000) assert.Equal(t, int64(5000), amount) }) t.Run("百分比佣金", func(t *testing.T) { allocation := &model.ShopSeriesAllocation{ OneTimeCommissionType: "fixed", OneTimeCommissionMode: "percent", OneTimeCommissionValue: 100, // 10% } amount := service.calculateOneTimeCommission(allocation, 10000) assert.Equal(t, int64(1000), amount) // 10000 * 100 / 1000 = 1000 }) t.Run("梯度佣金不处理", func(t *testing.T) { allocation := &model.ShopSeriesAllocation{ OneTimeCommissionType: "tiered", OneTimeCommissionMode: "fixed", OneTimeCommissionValue: 5000, } amount := service.calculateOneTimeCommission(allocation, 10000) assert.Equal(t, int64(0), amount) // 梯度佣金返回0,由其他服务处理 }) } // TestService_GetRechargeCheck_Device 测试设备类型的充值预检 func TestService_GetRechargeCheck_Device(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("设备资源_无强充要求", func(t *testing.T) { device := createTestDevice(t, tx, nil, nil) result, err := service.GetRechargeCheck(ctx, "device", device.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) assert.Equal(t, int64(constants.RechargeMinAmount), result.MinAmount) assert.Equal(t, int64(constants.RechargeMaxAmount), result.MaxAmount) }) t.Run("设备资源_需要强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 20000, false, 0) device := createTestDevice(t, tx, &shop.ID, &allocation.ID) result, err := service.GetRechargeCheck(ctx, "device", device.ID) require.NoError(t, err) assert.True(t, result.NeedForceRecharge) assert.Equal(t, int64(20000), result.ForceRechargeAmount) }) t.Run("设备资源不存在", func(t *testing.T) { result, err := service.GetRechargeCheck(ctx, "device", 999999) assert.Error(t, err) assert.Nil(t, result) assert.Contains(t, err.Error(), "设备不存在") }) } // TestService_List_MoreFilters 测试更多列表筛选条件 func TestService_List_MoreFilters(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("钱包ID筛选", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建订单 timestamp := time.Now().UnixNano() recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 200, Updater: 200, }, UserID: 200, WalletID: wallet.ID, RechargeNo: fmt.Sprintf("RCH%d", timestamp), Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 按钱包ID筛选 req := &dto.RechargeListRequest{ Page: 1, PageSize: 10, WalletID: &wallet.ID, } resp, err := service.List(ctx, req, 200) require.NoError(t, err) assert.NotNil(t, resp) assert.Equal(t, int64(1), resp.Total) }) t.Run("时间范围筛选", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建订单 timestamp := time.Now().UnixNano() recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 201, Updater: 201, }, UserID: 201, WalletID: wallet.ID, RechargeNo: fmt.Sprintf("RCH%d", timestamp), Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 按时间范围筛选 startTime := time.Now().Add(-1 * time.Hour) endTime := time.Now().Add(1 * time.Hour) req := &dto.RechargeListRequest{ Page: 1, PageSize: 10, StartTime: &startTime, EndTime: &endTime, } resp, err := service.List(ctx, req, 201) require.NoError(t, err) assert.NotNil(t, resp) assert.GreaterOrEqual(t, resp.Total, int64(1)) }) t.Run("默认分页参数", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 创建订单 timestamp := time.Now().UnixNano() recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 202, Updater: 202, }, UserID: 202, WalletID: wallet.ID, RechargeNo: fmt.Sprintf("RCH%d", timestamp), Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 不传分页参数 req := &dto.RechargeListRequest{} resp, err := service.List(ctx, req, 202) require.NoError(t, err) assert.NotNil(t, resp) assert.Equal(t, 1, resp.Page) assert.Equal(t, constants.DefaultPageSize, resp.PageSize) }) } // TestService_HandlePaymentCallback_Device 测试设备类型的支付回调 func TestService_HandlePaymentCallback_Device(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("设备充值_触发佣金", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 10000, false, 0) device := createTestDevice(t, tx, &shop.ID, &allocation.ID) wallet := createTestWallet(t, tx, "device", device.ID, "main") createTestWallet(t, tx, "shop", shop.ID, "commission") // 创建待支付订单 rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 处理回调 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) // 验证设备的 FirstCommissionPaid 已更新 var updatedDevice model.Device err = tx.First(&updatedDevice, device.ID).Error require.NoError(t, err) assert.True(t, updatedDevice.FirstCommissionPaid) assert.Equal(t, int64(10000), updatedDevice.AccumulatedRecharge) }) t.Run("设备充值_无店铺归属_跳过佣金", func(t *testing.T) { // 创建无店铺归属的设备 allocation := createTestSeriesAllocation(t, tx, 1, true, "single_recharge", 10000, false, 0) device := createTestDevice(t, tx, nil, &allocation.ID) // 无店铺 wallet := createTestWallet(t, tx, "device", device.ID, "main") // 创建待支付订单 rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 处理回调 - 应该成功但不发放佣金 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) // 验证钱包余额已更新 var updatedWallet model.Wallet err = tx.First(&updatedWallet, wallet.ID).Error require.NoError(t, err) assert.Equal(t, int64(10000), updatedWallet.Balance) }) } // TestService_buildRechargeResponse_AllStatus 测试所有状态的响应构建 func TestService_buildRechargeResponse_AllStatus(t *testing.T) { service, tx := setupTestService(t) testCases := []struct { status int statusText string }{ {constants.RechargeStatusPending, "待支付"}, {constants.RechargeStatusPaid, "已支付"}, {constants.RechargeStatusCompleted, "已完成"}, {constants.RechargeStatusClosed, "已关闭"}, {constants.RechargeStatusRefunded, "已退款"}, } for _, tc := range testCases { t.Run(fmt.Sprintf("状态_%s", tc.statusText), func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") now := time.Now() paymentChannel := "jsapi" paymentTxID := "TX123" recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: fmt.Sprintf("RCH%d%d", time.Now().UnixNano(), tc.status), Amount: 10000, PaymentMethod: "wechat", PaymentChannel: &paymentChannel, PaymentTransactionID: &paymentTxID, Status: tc.status, PaidAt: &now, CompletedAt: &now, } require.NoError(t, tx.Create(recharge).Error) resp := service.buildRechargeResponse(recharge) assert.Equal(t, tc.status, resp.Status) assert.Equal(t, tc.statusText, resp.StatusText) assert.Equal(t, "wechat", resp.PaymentMethod) assert.NotNil(t, resp.PaymentChannel) assert.Equal(t, "jsapi", *resp.PaymentChannel) assert.NotNil(t, resp.PaymentTransactionID) assert.Equal(t, "TX123", *resp.PaymentTransactionID) assert.NotNil(t, resp.PaidAt) assert.NotNil(t, resp.CompletedAt) }) } } // TestService_Create_Device 测试设备类型的创建 func TestService_Create_Device(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("设备钱包不存在", func(t *testing.T) { device := createTestDevice(t, tx, nil, nil) req := &dto.CreateRechargeRequest{ ResourceType: "device", ResourceID: device.ID, Amount: 10000, PaymentMethod: "wechat", } resp, err := service.Create(ctx, req, 1) assert.Error(t, err) assert.Nil(t, resp) assert.Contains(t, err.Error(), "钱包不存在") }) t.Run("设备强充金额不匹配", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 20000, false, 0) device := createTestDevice(t, tx, &shop.ID, &allocation.ID) createTestWallet(t, tx, "device", device.ID, "main") req := &dto.CreateRechargeRequest{ ResourceType: "device", ResourceID: device.ID, Amount: 10000, PaymentMethod: "wechat", } resp, err := service.Create(ctx, req, 1) assert.Error(t, err) assert.Nil(t, resp) assert.Contains(t, err.Error(), "强充要求") }) t.Run("设备成功创建充值订单", func(t *testing.T) { device := createTestDevice(t, tx, nil, nil) createTestWallet(t, tx, "device", device.ID, "main") req := &dto.CreateRechargeRequest{ ResourceType: "device", ResourceID: device.ID, Amount: 10000, PaymentMethod: "alipay", } resp, err := service.Create(ctx, req, 1) require.NoError(t, err) assert.NotNil(t, resp) assert.Equal(t, int64(10000), resp.Amount) assert.Equal(t, "alipay", resp.PaymentMethod) }) } // TestService_checkForceRechargeRequirement_MoreCases 测试更多强充验证场景 func TestService_checkForceRechargeRequirement_MoreCases(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("无系列分配_无需强充", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) result, err := service.checkForceRechargeRequirement(ctx, "iot_card", card.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) }) t.Run("系列分配不存在_无需强充", func(t *testing.T) { nonExistentID := uint(999999) card := createTestIotCard(t, tx, nil, &nonExistentID) result, err := service.checkForceRechargeRequirement(ctx, "iot_card", card.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) }) t.Run("累计充值触发_启用强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "accumulated_recharge", 50000, true, 15000) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) result, err := service.checkForceRechargeRequirement(ctx, "iot_card", card.ID) require.NoError(t, err) assert.True(t, result.NeedForceRecharge) assert.Equal(t, int64(15000), result.ForceRechargeAmount) assert.Equal(t, "accumulated_recharge", result.TriggerType) }) t.Run("未知触发类型_无需强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := &model.ShopSeriesAllocation{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ShopID: shop.ID, SeriesID: 1, AllocatorShopID: 0, BaseCommissionMode: "percent", BaseCommissionValue: 100, EnableOneTimeCommission: true, OneTimeCommissionType: "fixed", OneTimeCommissionTrigger: "unknown_trigger", OneTimeCommissionThreshold: 10000, OneTimeCommissionMode: "fixed", OneTimeCommissionValue: 5000, EnableForceRecharge: false, ForceRechargeAmount: 0, Status: 1, } require.NoError(t, tx.Create(allocation).Error) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) result, err := service.checkForceRechargeRequirement(ctx, "iot_card", card.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) }) t.Run("设备_累计充值触发_启用强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "accumulated_recharge", 50000, true, 15000) device := createTestDevice(t, tx, &shop.ID, &allocation.ID) result, err := service.checkForceRechargeRequirement(ctx, "device", device.ID) require.NoError(t, err) assert.True(t, result.NeedForceRecharge) assert.Equal(t, int64(15000), result.ForceRechargeAmount) }) t.Run("设备_佣金已发放_无需强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 10000, false, 0) device := createTestDevice(t, tx, &shop.ID, &allocation.ID) device.FirstCommissionPaid = true tx.Save(device) result, err := service.checkForceRechargeRequirement(ctx, "device", device.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) assert.True(t, result.FirstCommissionPaid) }) t.Run("设备_系列分配不存在_无需强充", func(t *testing.T) { nonExistentID := uint(999999) device := createTestDevice(t, tx, nil, &nonExistentID) result, err := service.checkForceRechargeRequirement(ctx, "device", device.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) }) t.Run("设备_无系列分配_无需强充", func(t *testing.T) { device := createTestDevice(t, tx, nil, nil) result, err := service.checkForceRechargeRequirement(ctx, "device", device.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) }) t.Run("设备_一次性佣金未启用_无需强充", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, false, "", 0, false, 0) device := createTestDevice(t, tx, &shop.ID, &allocation.ID) result, err := service.checkForceRechargeRequirement(ctx, "device", device.ID) require.NoError(t, err) assert.False(t, result.NeedForceRecharge) }) t.Run("累计充值触发_启用强充_无配置金额_使用阈值", func(t *testing.T) { shop := createTestShop(t, tx) allocation := &model.ShopSeriesAllocation{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ShopID: shop.ID, SeriesID: 1, AllocatorShopID: 0, BaseCommissionMode: "percent", BaseCommissionValue: 100, EnableOneTimeCommission: true, OneTimeCommissionType: "fixed", OneTimeCommissionTrigger: "accumulated_recharge", OneTimeCommissionThreshold: 50000, OneTimeCommissionMode: "fixed", OneTimeCommissionValue: 5000, EnableForceRecharge: true, ForceRechargeAmount: 0, Status: 1, } require.NoError(t, tx.Create(allocation).Error) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) result, err := service.checkForceRechargeRequirement(ctx, "iot_card", card.ID) require.NoError(t, err) assert.True(t, result.NeedForceRecharge) assert.Equal(t, int64(50000), result.ForceRechargeAmount) }) } // TestService_HandlePaymentCallback_MoreCases 测试更多支付回调场景 func TestService_HandlePaymentCallback_MoreCases(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("已支付状态_幂等返回成功", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPaid, } require.NoError(t, tx.Create(recharge).Error) err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) }) t.Run("已退款状态_不允许支付", func(t *testing.T) { card := createTestIotCard(t, tx, nil, nil) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusRefunded, } require.NoError(t, tx.Create(recharge).Error) err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") assert.Error(t, err) assert.Contains(t, err.Error(), "订单状态不允许支付") }) } // TestService_triggerOneTimeCommission_EdgeCases 测试一次性佣金触发的边界情况 func TestService_triggerOneTimeCommission_EdgeCases(t *testing.T) { service, tx := setupTestService(t) ctx := context.Background() t.Run("佣金金额为0_不发放", func(t *testing.T) { shop := createTestShop(t, tx) allocation := &model.ShopSeriesAllocation{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ShopID: shop.ID, SeriesID: 1, AllocatorShopID: 0, BaseCommissionMode: "percent", BaseCommissionValue: 100, EnableOneTimeCommission: true, OneTimeCommissionType: "fixed", OneTimeCommissionTrigger: "single_recharge", OneTimeCommissionThreshold: 10000, OneTimeCommissionMode: "fixed", OneTimeCommissionValue: 0, // 佣金金额为0 EnableForceRecharge: false, ForceRechargeAmount: 0, Status: 1, } require.NoError(t, tx.Create(allocation).Error) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") createTestWallet(t, tx, "shop", shop.ID, "commission") // 创建待支付订单 rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 处理回调 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) // 验证没有创建佣金记录 var commissionRecords []model.CommissionRecord err = tx.Where("iot_card_id = ?", card.ID).Find(&commissionRecords).Error require.NoError(t, err) assert.Len(t, commissionRecords, 0) }) t.Run("未达到阈值_不触发佣金", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 20000, false, 0) // 阈值200元 card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") createTestWallet(t, tx, "shop", shop.ID, "commission") // 创建待支付订单(金额低于阈值) rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, // 100元,低于200元阈值 PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 处理回调 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) // 验证没有创建佣金记录 var commissionRecords []model.CommissionRecord err = tx.Where("iot_card_id = ?", card.ID).Find(&commissionRecords).Error require.NoError(t, err) assert.Len(t, commissionRecords, 0) // 验证 FirstCommissionPaid 未更新 var updatedCard model.IotCard err = tx.First(&updatedCard, card.ID).Error require.NoError(t, err) assert.False(t, updatedCard.FirstCommissionPaid) }) t.Run("店铺佣金钱包不存在_跳过佣金", func(t *testing.T) { shop := createTestShop(t, tx) allocation := createTestSeriesAllocation(t, tx, shop.ID, true, "single_recharge", 10000, false, 0) card := createTestIotCard(t, tx, &shop.ID, &allocation.ID) wallet := createTestWallet(t, tx, "iot_card", card.ID, "main") // 不创建店铺佣金钱包 // 创建待支付订单 rechargeNo := fmt.Sprintf("RCH%d", time.Now().UnixNano()) recharge := &model.RechargeRecord{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, UserID: 1, WalletID: wallet.ID, RechargeNo: rechargeNo, Amount: 10000, PaymentMethod: "wechat", Status: constants.RechargeStatusPending, } require.NoError(t, tx.Create(recharge).Error) // 处理回调 - 应该成功但不发放佣金 err := service.HandlePaymentCallback(ctx, rechargeNo, "wechat", "TX123456") require.NoError(t, err) // 验证钱包余额已更新 var updatedWallet model.Wallet err = tx.First(&updatedWallet, wallet.ID).Error require.NoError(t, err) assert.Equal(t, int64(10000), updatedWallet.Balance) }) }