package commission_calculation import ( "context" "testing" "time" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/service/commission_stats" "github.com/break/junhong_cmp_fiber/internal/store/postgres" "github.com/break/junhong_cmp_fiber/tests/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" ) func TestCalculateCommission_PurchaseOnBehalf(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) commissionRecordStore := postgres.NewCommissionRecordStore(tx, rdb) shopStore := postgres.NewShopStore(tx, rdb) shopSeriesAllocationStore := postgres.NewShopSeriesAllocationStore(tx) shopSeriesOneTimeCommissionTierStore := postgres.NewShopSeriesOneTimeCommissionTierStore(tx) iotCardStore := postgres.NewIotCardStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) walletStore := postgres.NewWalletStore(tx, rdb) walletTransactionStore := postgres.NewWalletTransactionStore(tx, rdb) orderStore := postgres.NewOrderStore(tx, rdb) orderItemStore := postgres.NewOrderItemStore(tx, rdb) packageStore := postgres.NewPackageStore(tx) statsStore := postgres.NewShopSeriesCommissionStatsStore(tx) commissionStatsService := commission_stats.New(statsStore) service := New( tx, commissionRecordStore, shopStore, shopSeriesAllocationStore, shopSeriesOneTimeCommissionTierStore, iotCardStore, deviceStore, walletStore, walletTransactionStore, orderStore, orderItemStore, packageStore, commissionStatsService, zap.NewNop(), ) ctx := context.Background() shop := &model.Shop{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ShopName: "测试店铺", ShopCode: "TEST001", ContactName: "测试联系人", ContactPhone: "13800000001", } require.NoError(t, tx.Create(shop).Error) wallet := &model.Wallet{ ResourceType: "shop", ResourceID: shop.ID, WalletType: "commission", Balance: 0, Version: 1, BaseModel: model.BaseModel{Creator: 1, Updater: 1}, } require.NoError(t, tx.Create(wallet).Error) allocation := &model.ShopSeriesAllocation{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ShopID: shop.ID, SeriesID: 1, AllocatorShopID: 1, BaseCommissionMode: model.CommissionModeFixed, BaseCommissionValue: 5000, EnableOneTimeCommission: true, OneTimeCommissionTrigger: model.OneTimeCommissionTriggerAccumulatedRecharge, OneTimeCommissionThreshold: 10000, OneTimeCommissionType: model.OneTimeCommissionTypeFixed, OneTimeCommissionMode: model.CommissionModeFixed, OneTimeCommissionValue: 1000, Status: 1, } require.NoError(t, tx.Create(allocation).Error) card := &model.IotCard{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ICCID: "89860000000000000001", ShopID: &shop.ID, SeriesAllocationID: &allocation.ID, AccumulatedRecharge: 0, FirstCommissionPaid: false, } require.NoError(t, tx.Create(card).Error) seriesID := allocation.SeriesID tests := []struct { name string isPurchaseOnBehalf bool expectedAccumulatedRecharge int64 expectedCommissionRecords int expectedOneTimeCommission bool }{ { name: "普通订单_触发累计充值和一次性佣金", isPurchaseOnBehalf: false, expectedAccumulatedRecharge: 15000, expectedCommissionRecords: 2, expectedOneTimeCommission: true, }, { name: "代购订单_不触发累计充值和一次性佣金", isPurchaseOnBehalf: true, expectedAccumulatedRecharge: 0, expectedCommissionRecords: 1, expectedOneTimeCommission: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { require.NoError(t, tx.Model(&model.IotCard{}).Where("id = ?", card.ID).Updates(map[string]interface{}{ "accumulated_recharge": 0, "first_commission_paid": false, }).Error) require.NoError(t, tx.Where("1=1").Delete(&model.CommissionRecord{}).Error) require.NoError(t, tx.Where("1=1").Delete(&model.Order{}).Error) order := &model.Order{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, OrderNo: "ORD" + time.Now().Format("20060102150405"), OrderType: model.OrderTypeSingleCard, IotCardID: &card.ID, BuyerType: model.BuyerTypeAgent, BuyerID: shop.ID, SellerShopID: &shop.ID, SeriesID: &seriesID, TotalAmount: 15000, SellerCostPrice: 5000, IsPurchaseOnBehalf: tt.isPurchaseOnBehalf, CommissionStatus: model.CommissionStatusPending, PaymentStatus: model.PaymentStatusPaid, } require.NoError(t, tx.Create(order).Error) err := service.CalculateCommission(ctx, order.ID) require.NoError(t, err) var updatedCard model.IotCard require.NoError(t, tx.First(&updatedCard, card.ID).Error) assert.Equal(t, tt.expectedAccumulatedRecharge, updatedCard.AccumulatedRecharge, "累计充值金额不符合预期") var records []model.CommissionRecord require.NoError(t, tx.Where("order_id = ?", order.ID).Find(&records).Error) assert.Equal(t, tt.expectedCommissionRecords, len(records), "佣金记录数量不符合预期") hasOneTimeCommission := false for _, record := range records { if record.CommissionSource == model.CommissionSourceOneTime { hasOneTimeCommission = true break } } assert.Equal(t, tt.expectedOneTimeCommission, hasOneTimeCommission, "一次性佣金触发状态不符合预期") if tt.expectedOneTimeCommission { assert.True(t, updatedCard.FirstCommissionPaid, "首次佣金发放标记应为true") } else { assert.False(t, updatedCard.FirstCommissionPaid, "首次佣金发放标记应为false") } }) } } func TestCalculateCommission_Device_PurchaseOnBehalf(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) commissionRecordStore := postgres.NewCommissionRecordStore(tx, rdb) shopStore := postgres.NewShopStore(tx, rdb) shopSeriesAllocationStore := postgres.NewShopSeriesAllocationStore(tx) shopSeriesOneTimeCommissionTierStore := postgres.NewShopSeriesOneTimeCommissionTierStore(tx) iotCardStore := postgres.NewIotCardStore(tx, rdb) deviceStore := postgres.NewDeviceStore(tx, rdb) walletStore := postgres.NewWalletStore(tx, rdb) walletTransactionStore := postgres.NewWalletTransactionStore(tx, rdb) orderStore := postgres.NewOrderStore(tx, rdb) orderItemStore := postgres.NewOrderItemStore(tx, rdb) packageStore := postgres.NewPackageStore(tx) statsStore := postgres.NewShopSeriesCommissionStatsStore(tx) commissionStatsService := commission_stats.New(statsStore) service := New( tx, commissionRecordStore, shopStore, shopSeriesAllocationStore, shopSeriesOneTimeCommissionTierStore, iotCardStore, deviceStore, walletStore, walletTransactionStore, orderStore, orderItemStore, packageStore, commissionStatsService, zap.NewNop(), ) ctx := context.Background() shop := &model.Shop{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ShopName: "测试店铺", ShopCode: "TEST002", ContactName: "测试联系人", ContactPhone: "13800000002", } require.NoError(t, tx.Create(shop).Error) wallet := &model.Wallet{ ResourceType: "shop", ResourceID: shop.ID, WalletType: "commission", Balance: 0, Version: 1, BaseModel: model.BaseModel{Creator: 1, Updater: 1}, } require.NoError(t, tx.Create(wallet).Error) allocation := &model.ShopSeriesAllocation{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, ShopID: shop.ID, SeriesID: 1, AllocatorShopID: 1, BaseCommissionMode: model.CommissionModeFixed, BaseCommissionValue: 5000, EnableOneTimeCommission: true, OneTimeCommissionTrigger: model.OneTimeCommissionTriggerAccumulatedRecharge, OneTimeCommissionThreshold: 10000, OneTimeCommissionType: model.OneTimeCommissionTypeFixed, OneTimeCommissionMode: model.CommissionModeFixed, OneTimeCommissionValue: 1000, Status: 1, } require.NoError(t, tx.Create(allocation).Error) device := &model.Device{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, DeviceNo: "DEV001", ShopID: &shop.ID, SeriesAllocationID: &allocation.ID, AccumulatedRecharge: 0, FirstCommissionPaid: false, } require.NoError(t, tx.Create(device).Error) seriesID := allocation.SeriesID tests := []struct { name string isPurchaseOnBehalf bool expectedAccumulatedRecharge int64 expectedCommissionRecords int expectedOneTimeCommission bool }{ { name: "普通订单_触发累计充值和一次性佣金", isPurchaseOnBehalf: false, expectedAccumulatedRecharge: 15000, expectedCommissionRecords: 2, expectedOneTimeCommission: true, }, { name: "代购订单_不触发累计充值和一次性佣金", isPurchaseOnBehalf: true, expectedAccumulatedRecharge: 0, expectedCommissionRecords: 1, expectedOneTimeCommission: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { require.NoError(t, tx.Model(&model.Device{}).Where("id = ?", device.ID).Updates(map[string]interface{}{ "accumulated_recharge": 0, "first_commission_paid": false, }).Error) require.NoError(t, tx.Where("1=1").Delete(&model.CommissionRecord{}).Error) require.NoError(t, tx.Where("1=1").Delete(&model.Order{}).Error) order := &model.Order{ BaseModel: model.BaseModel{ Creator: 1, Updater: 1, }, OrderNo: "ORD" + time.Now().Format("20060102150405"), OrderType: model.OrderTypeDevice, DeviceID: &device.ID, BuyerType: model.BuyerTypeAgent, BuyerID: shop.ID, SellerShopID: &shop.ID, SeriesID: &seriesID, TotalAmount: 15000, SellerCostPrice: 5000, IsPurchaseOnBehalf: tt.isPurchaseOnBehalf, CommissionStatus: model.CommissionStatusPending, PaymentStatus: model.PaymentStatusPaid, } require.NoError(t, tx.Create(order).Error) err := service.CalculateCommission(ctx, order.ID) require.NoError(t, err) var updatedDevice model.Device require.NoError(t, tx.First(&updatedDevice, device.ID).Error) assert.Equal(t, tt.expectedAccumulatedRecharge, updatedDevice.AccumulatedRecharge, "累计充值金额不符合预期") var records []model.CommissionRecord require.NoError(t, tx.Where("order_id = ?", order.ID).Find(&records).Error) assert.Equal(t, tt.expectedCommissionRecords, len(records), "佣金记录数量不符合预期") hasOneTimeCommission := false for _, record := range records { if record.CommissionSource == model.CommissionSourceOneTime { hasOneTimeCommission = true break } } assert.Equal(t, tt.expectedOneTimeCommission, hasOneTimeCommission, "一次性佣金触发状态不符合预期") if tt.expectedOneTimeCommission { assert.True(t, updatedDevice.FirstCommissionPaid, "首次佣金发放标记应为true") } else { assert.False(t, updatedDevice.FirstCommissionPaid, "首次佣金发放标记应为false") } }) } }