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