fix: 修复C端订单差价佣金计算错误及自动购包订单系列ID缺失问题
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m11s

- C端普通订单(createPackageOrder)创建时未设置 SellerCostPrice,
  导致底层店铺得到整个零售价作为差价佣金,上级代理链无法获得任何佣金。
  修复:在 createPackageOrder 中查询卖家成本价并写入订单字段。

- purchase_validation 新增 GetCostPrice 方法,供 C 端订单查询代理渠道成本价。

- auto_purchase 自动购包订单未设置 SeriesID 和 SellerCostPrice,
  导致差价佣金计算被整体跳过。修复:在 ProcessTask 中从卡/设备获取
  SeriesID,从套餐分配记录获取 SellerCostPrice,传入 buildOrderAndItems。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 13:35:13 +08:00
parent 6dfc5c0301
commit c1cec0aede
3 changed files with 101 additions and 22 deletions

View File

@@ -24,15 +24,18 @@ type AutoPurchasePayload struct {
// AutoPurchaseHandler 充值后自动购包任务处理器
type AutoPurchaseHandler struct {
db *gorm.DB
orderStore *postgres.OrderStore
rechargeRecordStore *postgres.AssetRechargeStore
walletStore *postgres.AssetWalletStore
walletTransactionStore *postgres.AssetWalletTransactionStore
packageUsageStore *postgres.PackageUsageStore
redis *redis.Client
asynqClient *asynq.Client // 用于事务提交成功后触发佣金计算任务
logger *zap.Logger
db *gorm.DB
orderStore *postgres.OrderStore
rechargeRecordStore *postgres.AssetRechargeStore
walletStore *postgres.AssetWalletStore
walletTransactionStore *postgres.AssetWalletTransactionStore
packageUsageStore *postgres.PackageUsageStore
shopPackageAllocationStore *postgres.ShopPackageAllocationStore // 用于查询卖家成本价
iotCardStore *postgres.IotCardStore // 用于获取卡的系列ID
deviceStore *postgres.DeviceStore // 用于获取设备的系列ID
redis *redis.Client
asynqClient *asynq.Client // 用于事务提交成功后触发佣金计算任务
logger *zap.Logger
}
// NewAutoPurchaseHandler 创建充值后自动购包处理器
@@ -64,15 +67,18 @@ func NewAutoPurchaseHandler(
}
return &AutoPurchaseHandler{
db: db,
orderStore: orderStore,
rechargeRecordStore: rechargeRecordStore,
walletStore: walletStore,
walletTransactionStore: walletTransactionStore,
packageUsageStore: packageUsageStore,
redis: redisClient,
asynqClient: asynqClient,
logger: logger,
db: db,
orderStore: orderStore,
rechargeRecordStore: rechargeRecordStore,
walletStore: walletStore,
walletTransactionStore: walletTransactionStore,
packageUsageStore: packageUsageStore,
shopPackageAllocationStore: postgres.NewShopPackageAllocationStore(db),
iotCardStore: postgres.NewIotCardStore(db, redisClient),
deviceStore: postgres.NewDeviceStore(db, redisClient),
redis: redisClient,
asynqClient: asynqClient,
logger: logger,
}
}
@@ -124,6 +130,43 @@ func (h *AutoPurchaseHandler) ProcessTask(ctx context.Context, task *asynq.Task)
return err
}
// 获取资产系列ID用于差价佣金和一次性佣金计算
var seriesID *uint
if rechargeRecord.LinkedCarrierID != nil && *rechargeRecord.LinkedCarrierID > 0 {
if rechargeRecord.LinkedCarrierType == "card" || rechargeRecord.LinkedCarrierType == constants.AssetWalletResourceTypeIotCard {
if card, cardErr := h.iotCardStore.GetByID(ctx, *rechargeRecord.LinkedCarrierID); cardErr == nil {
seriesID = card.SeriesID
} else {
h.logger.Warn("自动购包获取卡系列ID失败",
zap.Uint("card_id", *rechargeRecord.LinkedCarrierID),
zap.Error(cardErr))
}
} else if rechargeRecord.LinkedCarrierType == "device" || rechargeRecord.LinkedCarrierType == constants.AssetWalletResourceTypeDevice {
if device, deviceErr := h.deviceStore.GetByID(ctx, *rechargeRecord.LinkedCarrierID); deviceErr == nil {
seriesID = device.SeriesID
} else {
h.logger.Warn("自动购包获取设备系列ID失败",
zap.Uint("device_id", *rechargeRecord.LinkedCarrierID),
zap.Error(deviceErr))
}
}
}
// 获取卖家成本价,用于差价佣金链式计算的起点
// 平台直销ShopIDTag == 0时成本价为 0差价佣金计算会直接跳过
var sellerCostPrice int64
if rechargeRecord.ShopIDTag > 0 && len(packages) > 0 {
allocation, allocErr := h.shopPackageAllocationStore.GetByShopAndPackageForSystem(ctx, rechargeRecord.ShopIDTag, packages[0].ID)
if allocErr == nil {
sellerCostPrice = allocation.CostPrice
} else {
h.logger.Warn("自动购包获取卖家成本价失败差价佣金将计算为0",
zap.Uint("shop_id", rechargeRecord.ShopIDTag),
zap.Uint("package_id", packages[0].ID),
zap.Error(allocErr))
}
}
var createdOrderID uint
if err := h.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
wallet, walletErr := h.walletStore.GetByID(ctx, rechargeRecord.AssetWalletID)
@@ -142,7 +185,7 @@ func (h *AutoPurchaseHandler) ProcessTask(ctx context.Context, task *asynq.Task)
}
now := time.Now()
order, orderItems, buildErr := h.buildOrderAndItems(rechargeRecord, packages, totalAmount, now)
order, orderItems, buildErr := h.buildOrderAndItems(rechargeRecord, packages, totalAmount, seriesID, sellerCostPrice, now)
if buildErr != nil {
return buildErr
}
@@ -290,6 +333,8 @@ func (h *AutoPurchaseHandler) buildOrderAndItems(
rechargeRecord *model.AssetRechargeRecord,
packages []*model.Package,
totalAmount int64,
seriesID *uint,
sellerCostPrice int64,
now time.Time,
) (*model.Order, []*model.OrderItem, error) {
orderType, iotCardID, deviceID, err := parseLinkedCarrier(rechargeRecord.LinkedOrderType, rechargeRecord.LinkedCarrierType, rechargeRecord.LinkedCarrierID)
@@ -302,6 +347,12 @@ func (h *AutoPurchaseHandler) buildOrderAndItems(
generation = 1
}
var sellerShopID *uint
if rechargeRecord.ShopIDTag > 0 {
shopID := rechargeRecord.ShopIDTag
sellerShopID = &shopID
}
paidAmount := totalAmount
order := &model.Order{
BaseModel: model.BaseModel{
@@ -323,7 +374,9 @@ func (h *AutoPurchaseHandler) buildOrderAndItems(
Source: constants.OrderSourceClient,
Generation: generation,
ActualPaidAmount: &paidAmount,
SellerShopID: &rechargeRecord.ShopIDTag,
SellerShopID: sellerShopID,
SeriesID: seriesID,
SellerCostPrice: sellerCostPrice,
}
items := make([]*model.OrderItem, 0, len(packages))