送礼
This commit is contained in:
parent
17f2788dcf
commit
dc79adae36
@ -15,11 +15,11 @@ type DebitGiftCommand struct {
|
||||
GiftCount int32
|
||||
PriceVersion string
|
||||
RegionID int64
|
||||
// SenderRegionID 是送礼用户所属区域;用于按区域匹配礼物入主播周期钻石比例。
|
||||
// SenderRegionID 是送礼用户所属区域快照;保留给用户归属相关的账务审计和风控语义。
|
||||
SenderRegionID int64
|
||||
// TargetIsHost 只能由 gateway 根据 user-service active host profile 注入,客户端输入不可信。
|
||||
TargetIsHost bool
|
||||
// TargetHostRegionID 是主播身份所属区域;工资政策按该区域匹配,不能用房间可见区域替代。
|
||||
// TargetHostRegionID 是主播身份所属区域;主播周期钻石比例和工资政策均按该区域匹配,不能用房间可见区域替代。
|
||||
TargetHostRegionID int64
|
||||
// TargetAgencyOwnerUserID 是送礼瞬间主播上级代理的收款用户快照;结算按快照发放,避免月底组织变化错账。
|
||||
TargetAgencyOwnerUserID int64
|
||||
@ -41,7 +41,7 @@ type DebitGiftTargetCommand struct {
|
||||
TargetUserID int64
|
||||
// TargetIsHost 只能由 gateway 注入,批量目标之间不能共享该身份快照。
|
||||
TargetIsHost bool
|
||||
// TargetHostRegionID 是该目标主播身份所属区域。
|
||||
// TargetHostRegionID 是该目标主播身份所属区域;批量结算必须按每个目标自己的区域解析周期钻石比例。
|
||||
TargetHostRegionID int64
|
||||
// TargetAgencyOwnerUserID 是该目标主播当前代理 owner 收款快照。
|
||||
TargetAgencyOwnerUserID int64
|
||||
|
||||
@ -577,7 +577,7 @@ func TestDebitGiftAppliesGlobalDefaultGiftDiamondRatioToHeatValueByGiftType(t *t
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebitGiftUsesRegionalReturnCoinRatioWithoutChangingHostDiamonds(t *testing.T) {
|
||||
func TestDebitGiftUsesTargetHostRegionDiamondRatioAndRegionalReturnCoinRatio(t *testing.T) {
|
||||
repository := mysqltest.NewRepository(t)
|
||||
svc := walletservice.New(repository)
|
||||
repository.SetBalance(14501, 500)
|
||||
@ -602,8 +602,8 @@ func TestDebitGiftUsesRegionalReturnCoinRatioWithoutChangingHostDiamonds(t *test
|
||||
if err != nil {
|
||||
t.Fatalf("DebitGift regional return failed: %v", err)
|
||||
}
|
||||
if receipt.HeatValue != 100 || receipt.HostPeriodDiamondAdded != 100 {
|
||||
t.Fatalf("return coin ratio must not change heat or host diamonds: %+v", receipt)
|
||||
if receipt.HeatValue != 100 || receipt.HostPeriodDiamondAdded != 80 {
|
||||
t.Fatalf("host region ratio must change host diamonds without changing global room contribution: %+v", receipt)
|
||||
}
|
||||
balances, err := svc.GetBalances(context.Background(), 14502, []string{ledger.AssetCoin})
|
||||
if err != nil {
|
||||
@ -698,6 +698,39 @@ func TestBatchDebitGiftAppliesGlobalDefaultGiftDiamondRatioToEachTargetHeatValue
|
||||
}
|
||||
}
|
||||
|
||||
func TestBatchDebitGiftUsesEachTargetHostRegionDiamondRatioWithGlobalFallback(t *testing.T) {
|
||||
repository := mysqltest.NewRepository(t)
|
||||
repository.SetBalance(15101, 1000)
|
||||
repository.SetGiftPrice("batch-host-region-ratio-gift", "v1", 100, 100, 100)
|
||||
repository.SetGiftType("batch-host-region-ratio-gift", resourcedomain.GiftTypeNormal)
|
||||
repository.SetGiftDiamondRatio(7701, resourcedomain.GiftTypeNormal, "80.00")
|
||||
svc := walletservice.New(repository)
|
||||
|
||||
receipt, err := svc.BatchDebitGift(context.Background(), ledger.BatchDebitGiftCommand{
|
||||
CommandID: "cmd-batch-host-region-ratio",
|
||||
RoomID: "room-host-region-ratio",
|
||||
SenderUserID: 15101,
|
||||
SenderRegionID: 1001,
|
||||
RegionID: 9901,
|
||||
GiftID: "batch-host-region-ratio-gift",
|
||||
GiftCount: 1,
|
||||
PriceVersion: "v1",
|
||||
Targets: []ledger.DebitGiftTargetCommand{
|
||||
{CommandID: "cmd-batch-host-region-ratio:target:15102", TargetUserID: 15102, TargetIsHost: true, TargetHostRegionID: 7701},
|
||||
{CommandID: "cmd-batch-host-region-ratio:target:15103", TargetUserID: 15103, TargetIsHost: true, TargetHostRegionID: 7702},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("BatchDebitGift failed: %v", err)
|
||||
}
|
||||
if len(receipt.Targets) != 2 || receipt.Targets[0].Receipt.HostPeriodDiamondAdded != 80 || receipt.Targets[1].Receipt.HostPeriodDiamondAdded != 100 {
|
||||
t.Fatalf("batch host region ratio or global fallback mismatch: %+v", receipt)
|
||||
}
|
||||
if receipt.Targets[0].Receipt.HeatValue != 100 || receipt.Targets[1].Receipt.HeatValue != 100 {
|
||||
t.Fatalf("host region ratio must not change global room contribution: %+v", receipt)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDebitGiftRejectsHostPeriodWithoutRegion 锁定工资政策必须有主播区域才能入账。
|
||||
func TestDebitGiftRejectsHostPeriodWithoutRegion(t *testing.T) {
|
||||
repository := mysqltest.NewRepository(t)
|
||||
|
||||
@ -233,20 +233,28 @@ func (r *Repository) BatchDebitGift(ctx context.Context, command ledger.BatchDeb
|
||||
events = append(events, resourceEvent)
|
||||
}
|
||||
|
||||
anyHostTarget := false
|
||||
for _, target := range command.Targets {
|
||||
if target.TargetIsHost && !hostPointPolicies[target.CommandID].active {
|
||||
anyHostTarget = true
|
||||
break
|
||||
}
|
||||
type resolvedHostDiamondRatio struct {
|
||||
ratio giftDiamondRatioSnapshot
|
||||
effectiveRegionID int64
|
||||
}
|
||||
hostRatio := giftDiamondRatioSnapshot{Percent: "0.00", PPM: 0}
|
||||
hostRatioRegionID := int64(0)
|
||||
if anyHostTarget {
|
||||
hostRatio, hostRatioRegionID, err = r.resolveGlobalGiftDiamondRatio(ctx, tx, command.AppCode, giftConfig.GiftTypeCode)
|
||||
// 批量送礼中的主播可能属于不同区域,必须逐区域解析周期钻石比例;同一区域只查一次,
|
||||
// 解析器会在区域配置缺失时回退 region_id=0,既避免 N 次重复查询,也不混用其他主播区域。
|
||||
hostRatiosByRegion := make(map[int64]resolvedHostDiamondRatio)
|
||||
for _, target := range command.Targets {
|
||||
if !target.TargetIsHost || hostPointPolicies[target.CommandID].active {
|
||||
continue
|
||||
}
|
||||
if _, exists := hostRatiosByRegion[target.TargetHostRegionID]; exists {
|
||||
continue
|
||||
}
|
||||
ratio, effectiveRegionID, err := r.resolveGiftDiamondRatio(ctx, tx, command.AppCode, target.TargetHostRegionID, giftConfig.GiftTypeCode)
|
||||
if err != nil {
|
||||
return ledger.BatchGiftReceipt{}, err
|
||||
}
|
||||
hostRatiosByRegion[target.TargetHostRegionID] = resolvedHostDiamondRatio{
|
||||
ratio: ratio,
|
||||
effectiveRegionID: effectiveRegionID,
|
||||
}
|
||||
}
|
||||
|
||||
targetReceipts := make([]ledger.BatchGiftTargetReceipt, 0, len(command.Targets))
|
||||
@ -257,13 +265,16 @@ func (r *Repository) BatchDebitGift(ctx context.Context, command ledger.BatchDeb
|
||||
giftDiamondRatioPercent := "0.00"
|
||||
giftDiamondRatioRegionID := int64(0)
|
||||
if target.TargetIsHost && !hostPointPolicy.active {
|
||||
|
||||
hostPeriodDiamondAdded, err = giftDiamondAmount(chargeAmount, hostRatio.PPM)
|
||||
resolvedRatio, exists := hostRatiosByRegion[target.TargetHostRegionID]
|
||||
if !exists {
|
||||
return ledger.BatchGiftReceipt{}, xerr.New(xerr.Internal, "host gift diamond ratio is missing")
|
||||
}
|
||||
hostPeriodDiamondAdded, err = giftDiamondAmount(chargeAmount, resolvedRatio.ratio.PPM)
|
||||
if err != nil {
|
||||
return ledger.BatchGiftReceipt{}, err
|
||||
}
|
||||
giftDiamondRatioPercent = hostRatio.Percent
|
||||
giftDiamondRatioRegionID = hostRatioRegionID
|
||||
giftDiamondRatioPercent = resolvedRatio.ratio.Percent
|
||||
giftDiamondRatioRegionID = resolvedRatio.effectiveRegionID
|
||||
hostPeriodCycleKey = hostPeriodCycleKeyFromMS(nowMs)
|
||||
}
|
||||
|
||||
|
||||
@ -130,7 +130,9 @@ func (r *Repository) DebitGift(ctx context.Context, command ledger.DebitGiftComm
|
||||
giftDiamondRatioPercent := "0.00"
|
||||
giftDiamondRatioRegionID := int64(0)
|
||||
if command.TargetIsHost && !command.RobotGift && !hostPointPolicyActive {
|
||||
ratio, ratioRegionID, err := r.resolveGlobalGiftDiamondRatio(ctx, tx, command.AppCode, giftConfig.GiftTypeCode)
|
||||
// 主播周期钻石按主播身份所属区域结算,而不是房间可见区域或送礼人区域;
|
||||
// 区域未配置时由解析器回退 region_id=0,保证历史全局配置继续生效。
|
||||
ratio, ratioRegionID, err := r.resolveGiftDiamondRatio(ctx, tx, command.AppCode, command.TargetHostRegionID, giftConfig.GiftTypeCode)
|
||||
if err != nil {
|
||||
return ledger.Receipt{}, err
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user