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("等价抽数阶段门槛不正确");
|
errors.push("等价抽数阶段门槛不正确");
|
||||||
|
|
||||||
|
const jackpotMultipliers =
|
||||||
|
form.strategy_version === DYNAMIC_STRATEGY ? new Set(multiplierListFromForm(form.jackpot_multipliers)) : null;
|
||||||
|
|
||||||
// 阶段概率与 RTP 是两代策略共用的 owner 校验,fixed_v2 也不能跳过。
|
// 阶段概率与 RTP 是两代策略共用的 owner 校验,fixed_v2 也不能跳过。
|
||||||
for (const stageKey of ["novice", "normal", "advanced"]) {
|
for (const stageKey of ["novice", "normal", "advanced"]) {
|
||||||
const stage = form.stages?.find((item) => item.stage === stageKey);
|
const stage = form.stages?.find((item) => item.stage === stageKey);
|
||||||
@ -302,6 +305,19 @@ export function validateLuckyGiftForm(form) {
|
|||||||
errors.push(`${stageLabel(stageKey)}启用奖档概率必须大于 0`);
|
errors.push(`${stageLabel(stageKey)}启用奖档概率必须大于 0`);
|
||||||
if (enabled.some((tier) => Number(tier.multiplier) >= 10 && !tier.highWaterOnly))
|
if (enabled.some((tier) => Number(tier.multiplier) >= 10 && !tier.highWaterOnly))
|
||||||
errors.push(`${stageLabel(stageKey)}10x 及以上奖档必须限制为高水位`);
|
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 });
|
const expected = expectedRTPPercent(enabled, { multiplier: (item) => item.multiplier });
|
||||||
if (
|
if (
|
||||||
expected < number("target_rtp_percent") - number("control_band_percent") ||
|
expected < number("target_rtp_percent") - number("control_band_percent") ||
|
||||||
@ -333,11 +349,11 @@ export function validateLuckyGiftForm(form) {
|
|||||||
const jackpotTokens = String(form.jackpot_multipliers || "")
|
const jackpotTokens = String(form.jackpot_multipliers || "")
|
||||||
.split(/[,,\s]+/)
|
.split(/[,,\s]+/)
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
const jackpotMultipliers = multiplierListFromForm(form.jackpot_multipliers);
|
const jackpotMultiplierValues = multiplierListFromForm(form.jackpot_multipliers);
|
||||||
if (
|
if (
|
||||||
jackpotTokens.length !== jackpotMultipliers.length ||
|
jackpotTokens.length !== jackpotMultiplierValues.length ||
|
||||||
!jackpotMultipliers.length ||
|
!jackpotMultiplierValues.length ||
|
||||||
jackpotMultipliers.some((value, index) => value <= 1 || (index > 0 && value <= jackpotMultipliers[index - 1]))
|
jackpotMultiplierValues.some((value, index) => value <= 1 || (index > 0 && value <= jackpotMultiplierValues[index - 1]))
|
||||||
) {
|
) {
|
||||||
errors.push("大奖倍率必须大于 1x 并严格递增");
|
errors.push("大奖倍率必须大于 1x 并严格递增");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,7 +70,6 @@ describe("ops center lucky gift dynamic_v3 form", () => {
|
|||||||
const enabled = { ...draft, enabled: true };
|
const enabled = { ...draft, enabled: true };
|
||||||
const errors = validateLuckyGiftForm(enabled);
|
const errors = validateLuckyGiftForm(enabled);
|
||||||
|
|
||||||
expect(errors).toContain("启用前必须填写用户日累计消费触发门槛(金币)");
|
|
||||||
expect(errors).toContain("启用前普通阶段至少一个最低充值门槛必须大于 0");
|
expect(errors).toContain("启用前普通阶段至少一个最低充值门槛必须大于 0");
|
||||||
expect(errors).toContain("高阶充值门槛必须逐维不低于正常阶段且至少一项更高");
|
expect(errors).toContain("高阶充值门槛必须逐维不低于正常阶段且至少一项更高");
|
||||||
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");
|
||||||
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() {
|
function completeDynamicConfig() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user