feat(billing): 任务换额度定稿闭环——claim 凭据校验(40311)+ 定稿 4 任务目录
- claim_task_bonus 在幂等快捷路径前做完成凭据校验:report_feedback 查当日 rp_feedback、first_report 查 succeeded rp_report,无凭据 40311 且不打流水;sign_in/share_report 不校验(产品决策:签到行为即领取,分享内测期接受端侧自报,hard_cap 锁死刷量收益) - task_bonus_rules 默认值与 .env.example 同步产品定稿(产品方案 §3.2,2026-09-11):sign_in 对话+10/day、report_feedback 发型+2/day、share_report 换装+3/day、first_report 重生成+1/lifetime;下架 invite_friend/profile_complete - billing/repo 新增只读凭据探测 has_feedback_between/has_completed_report(import-linter 禁 billing→report,直查 shared.models 的 rp_* 表,永远只读) - 测试:test_task_bonus_eligibility 5 用例(40311 两分支/凭据后 200/40910/40410/零流水) 偏差说明:test_task_bonus 与 test_task_bonus_rules 断言数值随定稿更新(发放/幂等/封顶语义未动);quota.py docstring「占位值」说法顺手更正。
This commit is contained in:
@@ -14,13 +14,13 @@ import pytest
|
||||
from packages.domain.billing.quota import PERIOD_TYPES
|
||||
from packages.shared.config import Settings
|
||||
|
||||
#: FR-BILL-03 的五类任务:签到、完善资料、反馈、分享、邀请。
|
||||
_FR_BILL_03_TASKS = (
|
||||
#: 产品方案 §3.2 定稿目录(2026-09-11):签到、反馈、分享、首次速测;
|
||||
#: invite_friend/profile_complete 无可信完成信号,已下架(不在默认值里)。
|
||||
_FINAL_CATALOG_TASKS = (
|
||||
"sign_in",
|
||||
"profile_complete",
|
||||
"report_feedback",
|
||||
"share_report",
|
||||
"invite_friend",
|
||||
"first_report",
|
||||
)
|
||||
|
||||
|
||||
@@ -29,10 +29,13 @@ def _rules_without_env() -> dict[str, dict[str, object]]:
|
||||
return dict(Settings(_env_file=None).task_bonus_rules)
|
||||
|
||||
|
||||
def test_default_rules_cover_all_five_frbill03_tasks() -> None:
|
||||
def test_default_rules_cover_the_final_catalog() -> None:
|
||||
rules = _rules_without_env()
|
||||
for task_key in _FR_BILL_03_TASKS:
|
||||
for task_key in _FINAL_CATALOG_TASKS:
|
||||
assert task_key in rules, task_key
|
||||
# 下架任务不得出现在默认值里(不下发即下架,claim 返回 40410)。
|
||||
assert "invite_friend" not in rules
|
||||
assert "profile_complete" not in rules
|
||||
|
||||
|
||||
def test_every_default_rule_entry_has_a_valid_shape() -> None:
|
||||
@@ -42,7 +45,7 @@ def test_every_default_rule_entry_has_a_valid_shape() -> None:
|
||||
assert isinstance(quota_key, str) and quota_key, task_key
|
||||
amount = conf.get("amount")
|
||||
assert isinstance(amount, int) and not isinstance(amount, bool), task_key
|
||||
assert amount > 0, task_key # 占位值 1,正式数值由产品定稿后改 env
|
||||
assert amount > 0, task_key # 定稿数值(§3.2),改 env 即生效
|
||||
assert conf.get("claim_period") in PERIOD_TYPES, task_key
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user