fix(commission): 代购订单跳过一次性佣金和累计充值更新
This commit is contained in:
@@ -91,13 +91,16 @@ func (s *Service) CalculateCommission(ctx context.Context, orderID uint) error {
|
||||
}
|
||||
}
|
||||
|
||||
if order.OrderType == model.OrderTypeSingleCard && order.IotCardID != nil {
|
||||
if err := s.triggerOneTimeCommissionForCardInTx(ctx, tx, order, *order.IotCardID); err != nil {
|
||||
return errors.Wrap(errors.CodeInternalError, err, "触发单卡一次性佣金失败")
|
||||
}
|
||||
} else if order.OrderType == model.OrderTypeDevice && order.DeviceID != nil {
|
||||
if err := s.triggerOneTimeCommissionForDeviceInTx(ctx, tx, order, *order.DeviceID); err != nil {
|
||||
return errors.Wrap(errors.CodeInternalError, err, "触发设备一次性佣金失败")
|
||||
// 代购订单不触发一次性佣金和累计充值更新
|
||||
if !order.IsPurchaseOnBehalf {
|
||||
if order.OrderType == model.OrderTypeSingleCard && order.IotCardID != nil {
|
||||
if err := s.triggerOneTimeCommissionForCardInTx(ctx, tx, order, *order.IotCardID); err != nil {
|
||||
return errors.Wrap(errors.CodeInternalError, err, "触发单卡一次性佣金失败")
|
||||
}
|
||||
} else if order.OrderType == model.OrderTypeDevice && order.DeviceID != nil {
|
||||
if err := s.triggerOneTimeCommissionForDeviceInTx(ctx, tx, order, *order.DeviceID); err != nil {
|
||||
return errors.Wrap(errors.CodeInternalError, err, "触发设备一次性佣金失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +192,11 @@ func (s *Service) calculateCostPrice(allocation *model.ShopSeriesAllocation, ord
|
||||
}
|
||||
|
||||
func (s *Service) triggerOneTimeCommissionForCardInTx(ctx context.Context, tx *gorm.DB, order *model.Order, cardID uint) error {
|
||||
// 代购订单不触发一次性佣金和累计充值更新
|
||||
if order.IsPurchaseOnBehalf {
|
||||
return nil
|
||||
}
|
||||
|
||||
card, err := s.iotCardStore.GetByID(ctx, cardID)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "获取卡信息失败")
|
||||
@@ -284,6 +292,11 @@ func (s *Service) TriggerOneTimeCommissionForCard(ctx context.Context, order *mo
|
||||
}
|
||||
|
||||
func (s *Service) triggerOneTimeCommissionForDeviceInTx(ctx context.Context, tx *gorm.DB, order *model.Order, deviceID uint) error {
|
||||
// 代购订单不触发一次性佣金和累计充值更新
|
||||
if order.IsPurchaseOnBehalf {
|
||||
return nil
|
||||
}
|
||||
|
||||
device, err := s.deviceStore.GetByID(ctx, deviceID)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "获取设备信息失败")
|
||||
|
||||
369
internal/service/commission_calculation/service_test.go
Normal file
369
internal/service/commission_calculation/service_test.go
Normal file
@@ -0,0 +1,369 @@
|
||||
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")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user