Files
junhong_cmp_fiber/tests/unit/commission_calculation_service_test.go
huang fba8e9e76b
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m18s
refactor(account): 移除卡类型字段、优化账号列表查询和权限检查
- 移除 IoT 卡和号卡的 card_type 字段(数据库迁移)
- 优化账号列表查询,支持按店铺和企业筛选
- 账号响应增加店铺名称和企业名称字段
- 实现批量加载店铺和企业名称,避免 N+1 查询
- 更新权限检查中间件,完善权限验证逻辑
- 更新相关测试用例,确保功能正确性
2026-02-03 10:59:44 +08:00

411 lines
15 KiB
Go

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")
})
})
}