package unit import ( "context" "fmt" "testing" "time" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/internal/service/commission_calculation" "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/pkg/constants" "github.com/break/junhong_cmp_fiber/tests/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" ) func TestCommissionCalculation_AccumulatedRecharge(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) ctx := context.Background() t.Run("累计充值触发-每次支付都写回累计金额", func(t *testing.T) { shop := &model.Shop{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, ShopName: "测试店铺", ShopCode: fmt.Sprintf("SHOP_%d", time.Now().UnixNano()), Level: 1, Status: constants.StatusEnabled, } require.NoError(t, tx.Create(shop).Error) series := &model.PackageSeries{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, SeriesCode: fmt.Sprintf("SERIES_%d", time.Now().UnixNano()), SeriesName: "测试系列", Status: constants.StatusEnabled, } require.NoError(t, tx.Create(series).Error) allocation := &model.ShopSeriesAllocation{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, ShopID: shop.ID, SeriesID: series.ID, AllocatorShopID: 0, BaseCommissionMode: model.CommissionModeFixed, BaseCommissionValue: 1000, EnableOneTimeCommission: true, OneTimeCommissionType: model.OneTimeCommissionTypeFixed, OneTimeCommissionTrigger: model.OneTimeCommissionTriggerAccumulatedRecharge, OneTimeCommissionThreshold: 10000, OneTimeCommissionMode: model.CommissionModeFixed, OneTimeCommissionValue: 500, Status: constants.StatusEnabled, } require.NoError(t, tx.Create(allocation).Error) card := &model.IotCard{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, ICCID: fmt.Sprintf("898600%013d", time.Now().Unix()%10000000000000), CardCategory: "normal", CarrierID: 1, CarrierType: "CMCC", CarrierName: "中国移动", Status: 3, ShopID: &shop.ID, SeriesID: &allocation.ID, FirstCommissionPaid: false, AccumulatedRecharge: 0, } require.NoError(t, tx.Create(card).Error) wallet := &model.Wallet{ ResourceType: "shop", ResourceID: shop.ID, WalletType: "commission", Balance: 0, Version: 0, Status: 1, } require.NoError(t, tx.Create(wallet).Error) iotCardStore := postgres.NewIotCardStore(tx, rdb) shopSeriesAllocationStore := postgres.NewShopSeriesAllocationStore(tx) t.Run("第一次支付-累计金额更新为3000", func(t *testing.T) { order1 := &model.Order{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, OrderNo: fmt.Sprintf("ORDER_%d_1", time.Now().UnixNano()), OrderType: model.OrderTypeSingleCard, BuyerType: model.BuyerTypeAgent, BuyerID: shop.ID, IotCardID: &card.ID, SellerShopID: &shop.ID, SeriesID: &series.ID, TotalAmount: 3000, SellerCostPrice: 2000, PaymentStatus: model.PaymentStatusPaid, CommissionStatus: model.CommissionStatusPending, } require.NoError(t, tx.Create(order1).Error) cardBefore, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.Equal(t, int64(0), cardBefore.AccumulatedRecharge) alloc, err := shopSeriesAllocationStore.GetByID(ctx, *card.SeriesID) require.NoError(t, err) if alloc.OneTimeCommissionTrigger == model.OneTimeCommissionTriggerAccumulatedRecharge { newAccumulated := cardBefore.AccumulatedRecharge + order1.TotalAmount err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID). Update("accumulated_recharge", newAccumulated).Error require.NoError(t, err) } cardAfter, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.Equal(t, int64(3000), cardAfter.AccumulatedRecharge, "第一次支付后累计金额应为3000") assert.False(t, cardAfter.FirstCommissionPaid, "未达阈值不应标记为已发放") }) t.Run("第二次支付-累计金额更新为7000", func(t *testing.T) { order2 := &model.Order{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, OrderNo: fmt.Sprintf("ORDER_%d_2", time.Now().UnixNano()), OrderType: model.OrderTypeSingleCard, BuyerType: model.BuyerTypeAgent, BuyerID: shop.ID, IotCardID: &card.ID, SellerShopID: &shop.ID, SeriesID: &series.ID, TotalAmount: 4000, SellerCostPrice: 3000, PaymentStatus: model.PaymentStatusPaid, CommissionStatus: model.CommissionStatusPending, } require.NoError(t, tx.Create(order2).Error) cardBefore, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.Equal(t, int64(3000), cardBefore.AccumulatedRecharge) alloc, err := shopSeriesAllocationStore.GetByID(ctx, *card.SeriesID) require.NoError(t, err) if alloc.OneTimeCommissionTrigger == model.OneTimeCommissionTriggerAccumulatedRecharge { newAccumulated := cardBefore.AccumulatedRecharge + order2.TotalAmount err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID). Update("accumulated_recharge", newAccumulated).Error require.NoError(t, err) } cardAfter, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.Equal(t, int64(7000), cardAfter.AccumulatedRecharge, "第二次支付后累计金额应为7000") assert.False(t, cardAfter.FirstCommissionPaid, "仍未达阈值不应标记为已发放") }) t.Run("第三次支付-累计金额更新为11000且达到阈值", func(t *testing.T) { order3 := &model.Order{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, OrderNo: fmt.Sprintf("ORDER_%d_3", time.Now().UnixNano()), OrderType: model.OrderTypeSingleCard, BuyerType: model.BuyerTypeAgent, BuyerID: shop.ID, IotCardID: &card.ID, SellerShopID: &shop.ID, SeriesID: &series.ID, TotalAmount: 4000, SellerCostPrice: 3000, PaymentStatus: model.PaymentStatusPaid, CommissionStatus: model.CommissionStatusPending, } require.NoError(t, tx.Create(order3).Error) cardBefore, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.Equal(t, int64(7000), cardBefore.AccumulatedRecharge) alloc, err := shopSeriesAllocationStore.GetByID(ctx, *card.SeriesID) require.NoError(t, err) if alloc.OneTimeCommissionTrigger == model.OneTimeCommissionTriggerAccumulatedRecharge { newAccumulated := cardBefore.AccumulatedRecharge + order3.TotalAmount err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID). Update("accumulated_recharge", newAccumulated).Error require.NoError(t, err) } cardAfter, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.Equal(t, int64(11000), cardAfter.AccumulatedRecharge, "第三次支付后累计金额应为11000") if cardAfter.AccumulatedRecharge >= alloc.OneTimeCommissionThreshold && !cardAfter.FirstCommissionPaid { assert.GreaterOrEqual(t, cardAfter.AccumulatedRecharge, alloc.OneTimeCommissionThreshold, "累计金额已达阈值") err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID). Update("first_commission_paid", true).Error require.NoError(t, err) cardFinal, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.True(t, cardFinal.FirstCommissionPaid, "达到阈值应标记为已发放") } }) t.Run("第四次支付-累计金额继续更新但不重复发放", func(t *testing.T) { order4 := &model.Order{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, OrderNo: fmt.Sprintf("ORDER_%d_4", time.Now().UnixNano()), OrderType: model.OrderTypeSingleCard, BuyerType: model.BuyerTypeAgent, BuyerID: shop.ID, IotCardID: &card.ID, SellerShopID: &shop.ID, SeriesID: &series.ID, TotalAmount: 3000, SellerCostPrice: 2000, PaymentStatus: model.PaymentStatusPaid, CommissionStatus: model.CommissionStatusPending, } require.NoError(t, tx.Create(order4).Error) cardBefore, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.Equal(t, int64(11000), cardBefore.AccumulatedRecharge) assert.True(t, cardBefore.FirstCommissionPaid, "标记应保持为true") alloc, err := shopSeriesAllocationStore.GetByID(ctx, *card.SeriesID) require.NoError(t, err) if alloc.OneTimeCommissionTrigger == model.OneTimeCommissionTriggerAccumulatedRecharge { newAccumulated := cardBefore.AccumulatedRecharge + order4.TotalAmount err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID). Update("accumulated_recharge", newAccumulated).Error require.NoError(t, err) } cardAfter, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.Equal(t, int64(14000), cardAfter.AccumulatedRecharge, "第四次支付后累计金额应为14000") assert.True(t, cardAfter.FirstCommissionPaid, "已发放标记不应改变") }) }) } func TestCommissionCalculation_OneTimeCommissionLogic(t *testing.T) { tx := testutils.NewTestTransaction(t) rdb := testutils.GetTestRedis(t) testutils.CleanTestRedisKeys(t, rdb) ctx := context.Background() 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) shopSeriesCommissionStatsStore := postgres.NewShopSeriesCommissionStatsStore(tx) commissionStatsService := commission_stats.New(shopSeriesCommissionStatsStore) logger, _ := zap.NewDevelopment() commCalcService := commission_calculation.New( tx, commissionRecordStore, shopStore, shopSeriesAllocationStore, shopSeriesOneTimeCommissionTierStore, iotCardStore, deviceStore, walletStore, walletTransactionStore, orderStore, orderItemStore, packageStore, commissionStatsService, logger, ) t.Run("单次充值触发-达到阈值时发放佣金", func(t *testing.T) { shop := &model.Shop{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, ShopName: "单次触发店铺", ShopCode: fmt.Sprintf("SHOP_%d", time.Now().UnixNano()), Level: 1, Status: constants.StatusEnabled, } require.NoError(t, tx.Create(shop).Error) series := &model.PackageSeries{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, SeriesCode: fmt.Sprintf("SERIES_%d", time.Now().UnixNano()), SeriesName: "单次触发系列", Status: constants.StatusEnabled, } require.NoError(t, tx.Create(series).Error) allocation := &model.ShopSeriesAllocation{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, ShopID: shop.ID, SeriesID: series.ID, AllocatorShopID: 0, BaseCommissionMode: model.CommissionModeFixed, BaseCommissionValue: 500, EnableOneTimeCommission: true, OneTimeCommissionType: model.OneTimeCommissionTypeFixed, OneTimeCommissionTrigger: model.OneTimeCommissionTriggerSingleRecharge, OneTimeCommissionThreshold: 5000, OneTimeCommissionMode: model.CommissionModeFixed, OneTimeCommissionValue: 300, Status: constants.StatusEnabled, } require.NoError(t, tx.Create(allocation).Error) card := &model.IotCard{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, ICCID: fmt.Sprintf("898600%013d", time.Now().Unix()%10000000000000+1), CardCategory: "normal", CarrierID: 1, CarrierType: "CMCC", CarrierName: "中国移动", Status: 3, ShopID: &shop.ID, SeriesID: &allocation.ID, FirstCommissionPaid: false, AccumulatedRecharge: 0, } require.NoError(t, tx.Create(card).Error) wallet := &model.Wallet{ ResourceType: "shop", ResourceID: shop.ID, WalletType: "commission", Balance: 0, Version: 0, Status: 1, } require.NoError(t, tx.Create(wallet).Error) t.Run("单次充值未达阈值-不触发", func(t *testing.T) { order := &model.Order{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, OrderNo: fmt.Sprintf("ORDER_%d", time.Now().UnixNano()), OrderType: model.OrderTypeSingleCard, BuyerType: model.BuyerTypeAgent, BuyerID: shop.ID, IotCardID: &card.ID, SellerShopID: &shop.ID, SeriesID: &series.ID, TotalAmount: 3000, SellerCostPrice: 2500, PaymentStatus: model.PaymentStatusPaid, CommissionStatus: model.CommissionStatusPending, } require.NoError(t, tx.Create(order).Error) err := commCalcService.CalculateCommission(ctx, order.ID) require.NoError(t, err) cardAfter, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.False(t, cardAfter.FirstCommissionPaid, "单次充值未达阈值不应发放") }) t.Run("单次充值达到阈值-触发", func(t *testing.T) { order := &model.Order{ BaseModel: model.BaseModel{Creator: 1, Updater: 1}, OrderNo: fmt.Sprintf("ORDER_%d", time.Now().UnixNano()+1), OrderType: model.OrderTypeSingleCard, BuyerType: model.BuyerTypeAgent, BuyerID: shop.ID, IotCardID: &card.ID, SellerShopID: &shop.ID, SeriesID: &series.ID, TotalAmount: 6000, SellerCostPrice: 5500, PaymentStatus: model.PaymentStatusPaid, CommissionStatus: model.CommissionStatusPending, } require.NoError(t, tx.Create(order).Error) err := commCalcService.CalculateCommission(ctx, order.ID) require.NoError(t, err) cardAfter, err := iotCardStore.GetByID(ctx, card.ID) require.NoError(t, err) assert.True(t, cardAfter.FirstCommissionPaid, "单次充值达到阈值应发放") var commRecords []model.CommissionRecord err = tx.Where("order_id = ? AND commission_source = ?", order.ID, model.CommissionSourceOneTime). Find(&commRecords).Error require.NoError(t, err) assert.Len(t, commRecords, 1, "应有一条一次性佣金记录") assert.Equal(t, int64(300), commRecords[0].Amount, "佣金金额应为300") }) }) }