fix(ops): validate lucky gift jackpot tiers
This commit is contained in:
parent
17a94eaf94
commit
d2898f3fae
@ -284,6 +284,9 @@ export function validateLuckyGiftForm(form) {
|
||||
)
|
||||
errors.push("等价抽数阶段门槛不正确");
|
||||
|
||||
const jackpotMultipliers =
|
||||
form.strategy_version === DYNAMIC_STRATEGY ? new Set(multiplierListFromForm(form.jackpot_multipliers)) : null;
|
||||
|
||||
// 阶段概率与 RTP 是两代策略共用的 owner 校验,fixed_v2 也不能跳过。
|
||||
for (const stageKey of ["novice", "normal", "advanced"]) {
|
||||
const stage = form.stages?.find((item) => item.stage === stageKey);
|
||||
@ -302,6 +305,19 @@ export function validateLuckyGiftForm(form) {
|
||||
errors.push(`${stageLabel(stageKey)}启用奖档概率必须大于 0`);
|
||||
if (enabled.some((tier) => Number(tier.multiplier) >= 10 && !tier.highWaterOnly))
|
||||
errors.push(`${stageLabel(stageKey)}10x 及以上奖档必须限制为高水位`);
|
||||
const jackpotStageMultipliers =
|
||||
jackpotMultipliers &&
|
||||
enabled
|
||||
.filter(
|
||||
(tier) =>
|
||||
jackpotMultipliers.has(numberFromForm(tier.multiplier)) &&
|
||||
percentToPPM(tier.probabilityPercent) > 0,
|
||||
)
|
||||
.map((tier) => formatDecimal(numberFromForm(tier.multiplier)));
|
||||
if (jackpotStageMultipliers?.length) {
|
||||
// dynamic_v3 的大奖倍率只能走大奖补偿路径;普通阶段再给正概率会绕过 owner 的双 RTP 门槛。
|
||||
errors.push(`${stageLabel(stageKey)}普通奖档不能包含大奖倍率:${unique(jackpotStageMultipliers).join("x、")}x`);
|
||||
}
|
||||
const expected = expectedRTPPercent(enabled, { multiplier: (item) => item.multiplier });
|
||||
if (
|
||||
expected < number("target_rtp_percent") - number("control_band_percent") ||
|
||||
@ -333,11 +349,11 @@ export function validateLuckyGiftForm(form) {
|
||||
const jackpotTokens = String(form.jackpot_multipliers || "")
|
||||
.split(/[,,\s]+/)
|
||||
.filter(Boolean);
|
||||
const jackpotMultipliers = multiplierListFromForm(form.jackpot_multipliers);
|
||||
const jackpotMultiplierValues = multiplierListFromForm(form.jackpot_multipliers);
|
||||
if (
|
||||
jackpotTokens.length !== jackpotMultipliers.length ||
|
||||
!jackpotMultipliers.length ||
|
||||
jackpotMultipliers.some((value, index) => value <= 1 || (index > 0 && value <= jackpotMultipliers[index - 1]))
|
||||
jackpotTokens.length !== jackpotMultiplierValues.length ||
|
||||
!jackpotMultiplierValues.length ||
|
||||
jackpotMultiplierValues.some((value, index) => value <= 1 || (index > 0 && value <= jackpotMultiplierValues[index - 1]))
|
||||
) {
|
||||
errors.push("大奖倍率必须大于 1x 并严格递增");
|
||||
}
|
||||
|
||||
@ -70,7 +70,6 @@ describe("ops center lucky gift dynamic_v3 form", () => {
|
||||
const enabled = { ...draft, enabled: true };
|
||||
const errors = validateLuckyGiftForm(enabled);
|
||||
|
||||
expect(errors).toContain("启用前必须填写用户日累计消费触发门槛(金币)");
|
||||
expect(errors).toContain("启用前普通阶段至少一个最低充值门槛必须大于 0");
|
||||
expect(errors).toContain("高阶充值门槛必须逐维不低于正常阶段且至少一项更高");
|
||||
expect(errors).toContain("启用前必须填写单次返奖上限");
|
||||
@ -151,6 +150,32 @@ describe("ops center lucky gift dynamic_v3 form", () => {
|
||||
expect(errors).toContain("单次返奖上限不能小于 0");
|
||||
expect(errors).toContain("充值阶段门槛不能小于 0");
|
||||
});
|
||||
|
||||
test("rejects jackpot multipliers that still have ordinary stage probability", () => {
|
||||
const form = configToForm(completeDynamicConfig());
|
||||
const errors = validateLuckyGiftForm({
|
||||
...form,
|
||||
stages: form.stages.map((stage) =>
|
||||
stage.stage === "normal"
|
||||
? {
|
||||
...stage,
|
||||
tiers: [
|
||||
...stage.tiers,
|
||||
{
|
||||
enabled: true,
|
||||
highWaterOnly: true,
|
||||
multiplier: "200",
|
||||
probabilityPercent: "0.01",
|
||||
tierId: "normal_200x",
|
||||
},
|
||||
],
|
||||
}
|
||||
: stage,
|
||||
),
|
||||
});
|
||||
|
||||
expect(errors).toContain("正常阶段普通奖档不能包含大奖倍率:200x");
|
||||
});
|
||||
});
|
||||
|
||||
function completeDynamicConfig() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user