fix: settle gift contribution by coin spent
This commit is contained in:
parent
7a59d3571c
commit
b1a9d818aa
@ -75,7 +75,6 @@ type giftDTO struct {
|
||||
ChargeAssetType string `json:"chargeAssetType"`
|
||||
CoinPrice int64 `json:"coinPrice"`
|
||||
GiftPointAmount int64 `json:"giftPointAmount"`
|
||||
HeatValue int64 `json:"heatValue"`
|
||||
EffectiveFromMS int64 `json:"effectiveFromMs"`
|
||||
EffectiveToMS int64 `json:"effectiveToMs"`
|
||||
EffectTypes []string `json:"effectTypes"`
|
||||
@ -300,7 +299,6 @@ func giftFromProto(gift *walletv1.GiftConfig) giftDTO {
|
||||
ChargeAssetType: gift.GetChargeAssetType(),
|
||||
CoinPrice: gift.GetCoinPrice(),
|
||||
GiftPointAmount: gift.GetGiftPointAmount(),
|
||||
HeatValue: gift.GetHeatValue(),
|
||||
EffectiveFromMS: gift.GetEffectiveFromMs(),
|
||||
EffectiveToMS: gift.GetEffectiveToMs(),
|
||||
EffectTypes: gift.GetEffectTypes(),
|
||||
|
||||
@ -135,7 +135,7 @@ type giftRequest struct {
|
||||
ChargeAssetType string `json:"chargeAssetType"`
|
||||
CoinPrice int64 `json:"coinPrice"`
|
||||
GiftPointAmount int64 `json:"giftPointAmount"`
|
||||
HeatValue int64 `json:"heatValue"`
|
||||
HeatValue int64 `json:"heatValue"` // 兼容旧后台请求;新后台不再展示或提交热度。
|
||||
EffectiveAtMS int64 `json:"effectiveAtMs"`
|
||||
EffectiveFromMS int64 `json:"effectiveFromMs"`
|
||||
EffectiveToMS int64 `json:"effectiveToMs"`
|
||||
@ -371,7 +371,7 @@ func (r giftRequest) createProto(c *gin.Context) *walletv1.CreateGiftConfigReque
|
||||
ChargeAssetType: strings.TrimSpace(r.ChargeAssetType),
|
||||
CoinPrice: r.CoinPrice,
|
||||
GiftPointAmount: r.GiftPointAmount,
|
||||
HeatValue: r.HeatValue,
|
||||
HeatValue: r.CoinPrice,
|
||||
EffectiveAtMs: r.EffectiveAtMS,
|
||||
EffectiveFromMs: r.EffectiveFromMS,
|
||||
EffectiveToMs: r.EffectiveToMS,
|
||||
@ -396,7 +396,7 @@ func (r giftRequest) updateProto(c *gin.Context, giftID string) *walletv1.Update
|
||||
ChargeAssetType: strings.TrimSpace(r.ChargeAssetType),
|
||||
CoinPrice: r.CoinPrice,
|
||||
GiftPointAmount: r.GiftPointAmount,
|
||||
HeatValue: r.HeatValue,
|
||||
HeatValue: r.CoinPrice,
|
||||
EffectiveAtMs: r.EffectiveAtMS,
|
||||
EffectiveFromMs: r.EffectiveFromMS,
|
||||
EffectiveToMs: r.EffectiveToMS,
|
||||
|
||||
@ -54,7 +54,7 @@ func TestDebitGiftUsesServerPriceAndCreditsGiftPoint(t *testing.T) {
|
||||
t.Fatalf("DebitGift failed: %v", err)
|
||||
}
|
||||
|
||||
if receipt.CoinSpent != 14 || receipt.GiftPointAdded != 6 || receipt.HeatValue != 22 || receipt.BalanceAfter != 86 || receipt.PriceVersion != "v9" {
|
||||
if receipt.CoinSpent != 14 || receipt.GiftPointAdded != 6 || receipt.HeatValue != 14 || receipt.BalanceAfter != 86 || receipt.PriceVersion != "v9" {
|
||||
t.Fatalf("server price settlement mismatch: %+v", receipt)
|
||||
}
|
||||
if receipt.TransactionID == "" || receipt.BillingReceiptID == "" {
|
||||
@ -113,7 +113,7 @@ func TestBatchDebitGiftSettlesAllTargetsAtomically(t *testing.T) {
|
||||
t.Fatalf("BatchDebitGift failed: %v", err)
|
||||
}
|
||||
|
||||
if receipt.Aggregate.CoinSpent != 28 || receipt.Aggregate.GiftPointAdded != 12 || receipt.Aggregate.HeatValue != 44 || receipt.Aggregate.BalanceAfter != 72 || len(receipt.Targets) != 2 {
|
||||
if receipt.Aggregate.CoinSpent != 28 || receipt.Aggregate.GiftPointAdded != 12 || receipt.Aggregate.HeatValue != 28 || receipt.Aggregate.BalanceAfter != 72 || len(receipt.Targets) != 2 {
|
||||
t.Fatalf("batch aggregate mismatch: %+v", receipt)
|
||||
}
|
||||
for _, userID := range []int64{10002, 10003} {
|
||||
@ -272,21 +272,22 @@ func TestDebitGiftAppliesGlobalDefaultGiftDiamondRatioToHeatValueByGiftType(t *t
|
||||
repository.SetGiftDiamondRatio(8801, resourcedomain.GiftTypeSuperLucky, "50.00")
|
||||
|
||||
cases := []struct {
|
||||
giftID string
|
||||
giftType string
|
||||
command string
|
||||
senderID int64
|
||||
heatUnit int64
|
||||
wantHeat int64
|
||||
giftID string
|
||||
giftType string
|
||||
command string
|
||||
senderID int64
|
||||
coinPrice int64
|
||||
heatUnit int64
|
||||
wantHeat int64
|
||||
}{
|
||||
{giftID: "normal-room-ratio-gift", giftType: resourcedomain.GiftTypeNormal, command: "cmd-normal-room-ratio", senderID: 13001, heatUnit: 100, wantHeat: 100},
|
||||
{giftID: "lucky-room-ratio-gift", giftType: resourcedomain.GiftTypeLucky, command: "cmd-lucky-room-ratio", senderID: 13002, heatUnit: 100, wantHeat: 10},
|
||||
{giftID: "super-lucky-room-ratio-gift", giftType: resourcedomain.GiftTypeSuperLucky, command: "cmd-super-lucky-room-ratio", senderID: 13003, heatUnit: 99, wantHeat: 0},
|
||||
{giftID: "normal-room-ratio-gift", giftType: resourcedomain.GiftTypeNormal, command: "cmd-normal-room-ratio", senderID: 13001, coinPrice: 100, heatUnit: 999, wantHeat: 100},
|
||||
{giftID: "lucky-room-ratio-gift", giftType: resourcedomain.GiftTypeLucky, command: "cmd-lucky-room-ratio", senderID: 13002, coinPrice: 100, heatUnit: 999, wantHeat: 10},
|
||||
{giftID: "super-lucky-room-ratio-gift", giftType: resourcedomain.GiftTypeSuperLucky, command: "cmd-super-lucky-room-ratio", senderID: 13003, coinPrice: 200, heatUnit: 500, wantHeat: 2},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repository.SetBalance(tc.senderID, 100)
|
||||
repository.SetGiftPrice(tc.giftID, "v1", tc.heatUnit, 100, tc.heatUnit)
|
||||
repository.SetBalance(tc.senderID, 500)
|
||||
repository.SetGiftPrice(tc.giftID, "v1", tc.coinPrice, 100, tc.heatUnit)
|
||||
repository.SetGiftType(tc.giftID, tc.giftType)
|
||||
receipt, err := svc.DebitGift(context.Background(), ledger.DebitGiftCommand{
|
||||
CommandID: tc.command,
|
||||
@ -302,7 +303,7 @@ func TestDebitGiftAppliesGlobalDefaultGiftDiamondRatioToHeatValueByGiftType(t *t
|
||||
if err != nil {
|
||||
t.Fatalf("DebitGift %s failed: %v", tc.giftType, err)
|
||||
}
|
||||
if receipt.HeatValue != tc.wantHeat || receipt.GiftPointAdded != 100 || receipt.CoinSpent != tc.heatUnit {
|
||||
if receipt.HeatValue != tc.wantHeat || receipt.GiftPointAdded != 100 || receipt.CoinSpent != tc.coinPrice {
|
||||
t.Fatalf("%s room contribution ratio mismatch: %+v want heat %d", tc.giftType, receipt, tc.wantHeat)
|
||||
}
|
||||
}
|
||||
@ -311,7 +312,7 @@ func TestDebitGiftAppliesGlobalDefaultGiftDiamondRatioToHeatValueByGiftType(t *t
|
||||
func TestBatchDebitGiftAppliesGlobalDefaultGiftDiamondRatioToEachTargetHeatValue(t *testing.T) {
|
||||
repository := mysqltest.NewRepository(t)
|
||||
repository.SetBalance(15001, 1000)
|
||||
repository.SetGiftPrice("batch-room-ratio-gift", "v1", 100, 100, 100)
|
||||
repository.SetGiftPrice("batch-room-ratio-gift", "v1", 100, 100, 999)
|
||||
repository.SetGiftType("batch-room-ratio-gift", resourcedomain.GiftTypeLucky)
|
||||
repository.SetGiftDiamondRatio(9901, resourcedomain.GiftTypeLucky, "25.00")
|
||||
svc := walletservice.New(repository)
|
||||
@ -1085,7 +1086,7 @@ func TestGetUserGiftWallAggregatesSettledGifts(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("GetUserGiftWall failed: %v", err)
|
||||
}
|
||||
if wall.GiftKindCount != 2 || wall.GiftTotalCount != 6 || wall.TotalValue != 135 || wall.TotalGiftPoint != 65 || wall.TotalHeatValue != 255 {
|
||||
if wall.GiftKindCount != 2 || wall.GiftTotalCount != 6 || wall.TotalValue != 135 || wall.TotalGiftPoint != 65 || wall.TotalHeatValue != 135 {
|
||||
t.Fatalf("gift wall summary mismatch: %+v", wall)
|
||||
}
|
||||
rose, ok := giftWallItemByID(wall.Items, "rose")
|
||||
@ -2150,7 +2151,7 @@ func TestGiftConfigMustSelectGiftResource(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("DebitGift with resource-backed gift failed: %v", err)
|
||||
}
|
||||
if receipt.CoinSpent != 10 || receipt.GiftPointAdded != 4 || receipt.HeatValue != 18 {
|
||||
if receipt.CoinSpent != 10 || receipt.GiftPointAdded != 4 || receipt.HeatValue != 10 {
|
||||
t.Fatalf("resource-backed gift settlement mismatch: %+v", receipt)
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,16 +222,12 @@ func (r *Repository) DebitGift(ctx context.Context, command ledger.DebitGiftComm
|
||||
if err != nil {
|
||||
return ledger.Receipt{}, err
|
||||
}
|
||||
baseHeatValue, err := checkedMul(price.HeatValue, int64(command.GiftCount))
|
||||
if err != nil {
|
||||
return ledger.Receipt{}, err
|
||||
}
|
||||
roomContributionRatio, roomContributionRatioRegionID, err := r.resolveGlobalGiftDiamondRatio(ctx, tx, command.AppCode, giftConfig.GiftTypeCode)
|
||||
if err != nil {
|
||||
return ledger.Receipt{}, err
|
||||
}
|
||||
// 房间贡献统一按全局默认礼物比例折算;room-service 只消费结算后的 heat_value,不再自己查钱包配置。
|
||||
heatValue, err := giftDiamondAmount(baseHeatValue, roomContributionRatio.PPM)
|
||||
// 房间贡献只以真实扣费 COIN 为基数;旧 gift price heat_value 不再参与结算,避免后台热度配置覆盖实际消费。
|
||||
heatValue, err := giftDiamondAmount(chargeAmount, roomContributionRatio.PPM)
|
||||
if err != nil {
|
||||
return ledger.Receipt{}, err
|
||||
}
|
||||
@ -301,7 +297,7 @@ func (r *Repository) DebitGift(ctx context.Context, command ledger.DebitGiftComm
|
||||
RoomContributionRatioRegionID: roomContributionRatioRegionID,
|
||||
CoinPrice: price.CoinPrice,
|
||||
GiftPointAmount: price.GiftPointAmount,
|
||||
HeatUnitValue: price.HeatValue,
|
||||
HeatUnitValue: price.CoinPrice,
|
||||
}
|
||||
if err := r.insertTransaction(ctx, tx, transactionID, command.CommandID, bizTypeGiftDebit, requestHash, fmt.Sprintf("%s:%s", command.GiftID, price.PriceVersion), metadata, nowMs); err != nil {
|
||||
return ledger.Receipt{}, err
|
||||
@ -410,16 +406,12 @@ func (r *Repository) BatchDebitGift(ctx context.Context, command ledger.BatchDeb
|
||||
if err != nil {
|
||||
return ledger.BatchGiftReceipt{}, err
|
||||
}
|
||||
baseHeatValue, err := checkedMul(price.HeatValue, int64(command.GiftCount))
|
||||
if err != nil {
|
||||
return ledger.BatchGiftReceipt{}, err
|
||||
}
|
||||
roomContributionRatio, roomContributionRatioRegionID, err := r.resolveGlobalGiftDiamondRatio(ctx, tx, command.AppCode, giftConfig.GiftTypeCode)
|
||||
if err != nil {
|
||||
return ledger.BatchGiftReceipt{}, err
|
||||
}
|
||||
// 批量多目标仍然是每个目标各送一份同款礼物;每份房间贡献先按全局默认礼物比例折算,再由聚合回执累加。
|
||||
heatValue, err := giftDiamondAmount(baseHeatValue, roomContributionRatio.PPM)
|
||||
// 批量多目标仍然是每个目标各送一份同款礼物;每份房间贡献先按真实扣费折算,再由聚合回执累加。
|
||||
heatValue, err := giftDiamondAmount(chargeAmount, roomContributionRatio.PPM)
|
||||
if err != nil {
|
||||
return ledger.BatchGiftReceipt{}, err
|
||||
}
|
||||
@ -549,7 +541,7 @@ func (r *Repository) BatchDebitGift(ctx context.Context, command ledger.BatchDeb
|
||||
RoomContributionRatioRegionID: roomContributionRatioRegionID,
|
||||
CoinPrice: price.CoinPrice,
|
||||
GiftPointAmount: price.GiftPointAmount,
|
||||
HeatUnitValue: price.HeatValue,
|
||||
HeatUnitValue: price.CoinPrice,
|
||||
}
|
||||
if err := r.insertTransaction(ctx, tx, transactionID, target.CommandID, bizTypeGiftDebit, debitRequestHash(debitGiftCommandFromBatchTarget(command, target)), fmt.Sprintf("%s:%s", command.GiftID, price.PriceVersion), metadata, nowMs); err != nil {
|
||||
return ledger.BatchGiftReceipt{}, err
|
||||
|
||||
@ -628,7 +628,7 @@ func (r *Repository) ListGiftConfigs(ctx context.Context, query resourcedomain.L
|
||||
item.ChargeAssetType = price.ChargeAssetType
|
||||
item.CoinPrice = price.CoinPrice
|
||||
item.GiftPointAmount = price.GiftPointAmount
|
||||
item.HeatValue = price.HeatValue
|
||||
item.HeatValue = price.CoinPrice
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
@ -1952,6 +1952,7 @@ func (r *Repository) listResourceGrantItemsWithQuery(ctx context.Context, querie
|
||||
}
|
||||
|
||||
func (r *Repository) upsertGiftPriceTx(ctx context.Context, tx *sql.Tx, command resourcedomain.GiftConfigCommand, nowMs int64) error {
|
||||
legacyHeatValue := command.CoinPrice
|
||||
_, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO wallet_gift_prices (
|
||||
app_code, gift_id, price_version, status, charge_asset_type, coin_price, gift_point_amount,
|
||||
@ -1966,7 +1967,7 @@ func (r *Repository) upsertGiftPriceTx(ctx context.Context, tx *sql.Tx, command
|
||||
effective_at_ms = VALUES(effective_at_ms),
|
||||
updated_at_ms = VALUES(updated_at_ms)`,
|
||||
appcode.FromContext(ctx), command.GiftID, command.PriceVersion, command.ChargeAssetType, command.CoinPrice,
|
||||
command.GiftPointAmount, command.HeatValue, command.EffectiveAtMS, nowMs, nowMs,
|
||||
command.GiftPointAmount, legacyHeatValue, command.EffectiveAtMS, nowMs, nowMs,
|
||||
)
|
||||
return err
|
||||
}
|
||||
@ -2006,7 +2007,8 @@ func (r *Repository) getGiftConfig(ctx context.Context, giftID string) (resource
|
||||
gift.ChargeAssetType = price.ChargeAssetType
|
||||
gift.CoinPrice = price.CoinPrice
|
||||
gift.GiftPointAmount = price.GiftPointAmount
|
||||
gift.HeatValue = price.HeatValue
|
||||
// heat_value 是旧配置列,后台不再读写;对兼容调用方只回真实价格,房间贡献也按真实扣费结算。
|
||||
gift.HeatValue = price.CoinPrice
|
||||
}
|
||||
gift.RegionIDs, err = r.listGiftConfigRegionIDs(ctx, r.db, gift.GiftID)
|
||||
if err != nil {
|
||||
@ -3269,6 +3271,8 @@ func applyResourcePricingToGiftCommand(command resourcedomain.GiftConfigCommand,
|
||||
command.CoinPrice = 0
|
||||
command.GiftPointAmount = 0
|
||||
}
|
||||
// 后台已取消热度配置;旧列只保留兼容写入,数值始终跟真实 COIN 价格一致。
|
||||
command.HeatValue = command.CoinPrice
|
||||
return command
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user