feat: 接入数据大盘聚合与美团 CPS 对账
改了什么:新增新版大盘日期窗口聚合、广告收益拆分、比价耗时字段、美团 CPS 拉单入库与大盘展示,并同步反馈审核和邀请奖励下线口径。 验证:python -m pytest tests/test_admin_read.py tests/test_admin_write.py tests/test_compare_record.py tests/test_invite.py tests/test_feedback.py -q。
This commit is contained in:
+21
-23
@@ -1,4 +1,4 @@
|
||||
"""好友邀请测试:邀请码、绑定、双方发金币、幂等、自邀/无效码屏蔽、指纹兜底归因。
|
||||
"""好友邀请测试:邀请码、绑定、幂等、自邀/无效码屏蔽、指纹兜底归因。
|
||||
|
||||
用 sms mock 登录拿 token(同 test_welfare),再跑邀请闭环。
|
||||
"""
|
||||
@@ -10,8 +10,6 @@ from sqlalchemy import select
|
||||
|
||||
from app.core.rewards import (
|
||||
INVITE_FP_WINDOW_DAYS,
|
||||
INVITE_INVITEE_COINS,
|
||||
INVITE_INVITER_COINS,
|
||||
INVITE_NEW_USER_WINDOW_HOURS,
|
||||
)
|
||||
from app.db.session import SessionLocal
|
||||
@@ -56,8 +54,8 @@ def test_invite_me_returns_stable_code(client) -> None:
|
||||
assert _my_code(client, token) == body["invite_code"]
|
||||
|
||||
|
||||
def test_bind_flow_both_get_coins(client) -> None:
|
||||
"""B 用 A 的码绑定 → 双方各得 1 万金币;A 战绩 +1。"""
|
||||
def test_bind_flow_records_relation_without_invite_coins(client) -> None:
|
||||
"""B 用 A 的码绑定 → 邀请关系生效;邀请金币已下线。"""
|
||||
a = _login(client, "13800002002")
|
||||
b = _login(client, "13800002003")
|
||||
a_code = _my_code(client, a)
|
||||
@@ -69,20 +67,20 @@ def test_bind_flow_both_get_coins(client) -> None:
|
||||
assert r.status_code == 200, r.text
|
||||
res = r.json()
|
||||
assert res["status"] == "success"
|
||||
assert res["coins_awarded"] == INVITE_INVITEE_COINS
|
||||
assert res["coins_awarded"] == 0
|
||||
|
||||
# 双方金币到账
|
||||
assert _coin_balance(client, b) == INVITE_INVITEE_COINS
|
||||
assert _coin_balance(client, a) == INVITE_INVITER_COINS
|
||||
# 邀请金币已下线,双方余额不因邀请变化
|
||||
assert _coin_balance(client, b) == 0
|
||||
assert _coin_balance(client, a) == 0
|
||||
|
||||
# A 的战绩:已邀 1 人,累计获得 = 邀请人那份
|
||||
# A 的战绩:已邀 1 人,邀请金币保持 0
|
||||
r = client.get("/api/v1/invite/me", headers=_auth(a))
|
||||
assert r.json()["invited_count"] == 1
|
||||
assert r.json()["coins_earned"] == INVITE_INVITER_COINS
|
||||
assert r.json()["coins_earned"] == 0
|
||||
|
||||
|
||||
def test_bind_idempotent_no_double_reward(client) -> None:
|
||||
"""同一被邀请人二次绑定 → already_bound,不重复发奖。"""
|
||||
def test_bind_idempotent_no_duplicate_relation(client) -> None:
|
||||
"""同一被邀请人二次绑定 → already_bound,不重复绑定。"""
|
||||
a = _login(client, "13800002004")
|
||||
b = _login(client, "13800002005")
|
||||
a_code = _my_code(client, a)
|
||||
@@ -99,14 +97,14 @@ def test_bind_idempotent_no_double_reward(client) -> None:
|
||||
assert r2.json()["status"] == "already_bound"
|
||||
assert r2.json()["coins_awarded"] == 0
|
||||
|
||||
# 余额没变(没二次发奖),C 也没拿到邀请奖励
|
||||
# 余额没变,C 也没有邀请金币
|
||||
assert _coin_balance(client, b) == bal_b
|
||||
assert _coin_balance(client, a) == bal_a
|
||||
assert _coin_balance(client, c) == 0
|
||||
|
||||
|
||||
def test_self_invite_blocked(client) -> None:
|
||||
"""填自己的邀请码 → self_invite,不发奖。"""
|
||||
"""填自己的邀请码 → self_invite,不产生金币。"""
|
||||
a = _login(client, "13800002007")
|
||||
a_code = _my_code(client, a)
|
||||
r = client.post("/api/v1/invite/bind", json={"invite_code": a_code}, headers=_auth(a))
|
||||
@@ -116,7 +114,7 @@ def test_self_invite_blocked(client) -> None:
|
||||
|
||||
|
||||
def test_invalid_code(client) -> None:
|
||||
"""无效邀请码 → invalid_code,不发奖。"""
|
||||
"""无效邀请码 → invalid_code,不产生金币。"""
|
||||
b = _login(client, "13800002008")
|
||||
r = client.post("/api/v1/invite/bind", json={"invite_code": "ZZZZZZ"}, headers=_auth(b))
|
||||
assert r.status_code == 200, r.text
|
||||
@@ -145,7 +143,7 @@ def test_invite_requires_auth(client) -> None:
|
||||
|
||||
|
||||
def test_old_user_not_eligible(client) -> None:
|
||||
"""新用户闸:被邀请人注册超过窗口 → not_eligible,双方都不发奖。"""
|
||||
"""新用户闸:被邀请人注册超过窗口 → not_eligible,双方都不产生金币。"""
|
||||
a = _login(client, "13800002030")
|
||||
a_code = _my_code(client, a)
|
||||
b = _login(client, "13800002031")
|
||||
@@ -217,13 +215,13 @@ def test_bind_by_fingerprint_success(client) -> None:
|
||||
)
|
||||
assert r2.status_code == 200, r2.text
|
||||
assert r2.json()["status"] == "success"
|
||||
# 双方各发金币
|
||||
assert _coin_balance(client, a) == INVITE_INVITER_COINS
|
||||
assert _coin_balance(client, b) == INVITE_INVITEE_COINS
|
||||
# 邀请金币已下线,双方余额不因邀请变化
|
||||
assert _coin_balance(client, a) == 0
|
||||
assert _coin_balance(client, b) == 0
|
||||
|
||||
|
||||
def test_bind_by_fingerprint_not_found(client) -> None:
|
||||
"""没有匹配的指纹记录 → fp_not_found,不发奖。"""
|
||||
"""没有匹配的指纹记录 → fp_not_found,不产生金币。"""
|
||||
b = _login(client, "13800002043")
|
||||
r = client.post(
|
||||
"/api/v1/invite/bind",
|
||||
@@ -300,7 +298,7 @@ def test_bind_no_code_no_fingerprint(client) -> None:
|
||||
# =====================================================================
|
||||
|
||||
def test_invitees_basic(client) -> None:
|
||||
"""A 邀 B、C → 列表返 2 条、total=2、没设资料的名字=脱敏手机号、头像 null、金币对。"""
|
||||
"""A 邀 B、C → 列表返 2 条、total=2、没设资料的名字=脱敏手机号、头像 null、金币为 0。"""
|
||||
a = _login(client, "13800002050")
|
||||
a_code = _my_code(client, a)
|
||||
for phone in ("13800002051", "13800002052"):
|
||||
@@ -317,7 +315,7 @@ def test_invitees_basic(client) -> None:
|
||||
names = {it["display_name"] for it in body["items"]}
|
||||
assert names == {"138****2051", "138****2052"}
|
||||
assert all(it["avatar_url"] is None for it in body["items"])
|
||||
assert all(it["coins"] == INVITE_INVITER_COINS for it in body["items"])
|
||||
assert all(it["coins"] == 0 for it in body["items"])
|
||||
|
||||
|
||||
def test_invitees_order_desc(client) -> None:
|
||||
|
||||
Reference in New Issue
Block a user