19f5987436
Reviewed-on: #82 Co-authored-by: xiebing <xiebing@wonderable.ai> Co-committed-by: xiebing <xiebing@wonderable.ai>
115 lines
4.5 KiB
Python
115 lines
4.5 KiB
Python
"""邀请 v3 比价发奖测试:好友完成成功比价 → 邀请人得邀请奖励金(独立账户),幂等只发一次,
|
|
账户隔离不串金币/现金。被邀请人绑定不得任何奖励由 test_invite.py 覆盖。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from sqlalchemy import select
|
|
|
|
from app.core.rewards import INVITE_COMPARE_REWARD_CENTS
|
|
from app.db.session import SessionLocal
|
|
from app.models.wallet import CoinAccount, InviteCashTransaction
|
|
from app.repositories.user import get_user_by_phone
|
|
|
|
|
|
def _login(client, phone: str) -> str:
|
|
client.post("/api/v1/auth/sms/send", json={"phone": phone})
|
|
r = client.post("/api/v1/auth/sms/login", json={"phone": phone, "code": "123456"})
|
|
assert r.status_code == 200, r.text
|
|
return r.json()["access_token"]
|
|
|
|
|
|
def _auth(token: str) -> dict[str, str]:
|
|
return {"Authorization": f"Bearer {token}"}
|
|
|
|
|
|
def _my_code(client, token: str) -> str:
|
|
return client.get("/api/v1/invite/me", headers=_auth(token)).json()["invite_code"]
|
|
|
|
|
|
def _bind(client, token: str, code: str):
|
|
return client.post("/api/v1/invite/bind", json={"invite_code": code}, headers=_auth(token))
|
|
|
|
|
|
def _report_compare(client, token: str, trace_id: str, status: str = "success"):
|
|
return client.post(
|
|
"/api/v1/compare/record",
|
|
json={"trace_id": trace_id, "status": status},
|
|
headers=_auth(token),
|
|
)
|
|
|
|
|
|
def _invite_cash(phone: str) -> int:
|
|
"""被试用户的邀请奖励金余额(分)。专用查询端点见小步3,这里直接查 DB。"""
|
|
with SessionLocal() as db:
|
|
u = get_user_by_phone(db, phone)
|
|
acc = db.get(CoinAccount, u.id) if u else None
|
|
return acc.invite_cash_balance_cents if acc else 0
|
|
|
|
|
|
def test_compare_reward_granted_to_inviter(client) -> None:
|
|
"""B 被 A 邀请后完成一次成功比价 → A 得邀请奖励金 2 元(独立账户),B 不得该奖。"""
|
|
a = _login(client, "13800003001")
|
|
b = _login(client, "13800003002")
|
|
_bind(client, b, _my_code(client, a))
|
|
|
|
assert _invite_cash("13800003001") == 0 # 发奖前
|
|
|
|
r = _report_compare(client, b, "trace-reward-1")
|
|
assert r.status_code == 200, r.text
|
|
|
|
assert _invite_cash("13800003001") == INVITE_COMPARE_REWARD_CENTS # 邀请人到账
|
|
assert _invite_cash("13800003002") == 0 # 被邀请人不得此奖
|
|
|
|
|
|
def test_compare_reward_idempotent(client) -> None:
|
|
"""好友比价多次 → 只发一次(compare_reward_granted 幂等)。"""
|
|
a = _login(client, "13800003003")
|
|
b = _login(client, "13800003004")
|
|
_bind(client, b, _my_code(client, a))
|
|
|
|
_report_compare(client, b, "trace-idem-1")
|
|
_report_compare(client, b, "trace-idem-2") # 第二次比价(不同 trace)
|
|
_report_compare(client, b, "trace-idem-1") # 重复上报同 trace
|
|
|
|
assert _invite_cash("13800003003") == INVITE_COMPARE_REWARD_CENTS # 仍只发一次
|
|
|
|
|
|
def test_compare_no_relation_no_reward(client) -> None:
|
|
"""没有邀请关系的人比价 → 不发奖(没人是他的邀请人)。"""
|
|
x = _login(client, "13800003005")
|
|
r = _report_compare(client, x, "trace-norel-1")
|
|
assert r.status_code == 200, r.text
|
|
assert _invite_cash("13800003005") == 0
|
|
|
|
|
|
def test_compare_failed_no_reward(client) -> None:
|
|
"""失败的比价(status=failed)不触发发奖。"""
|
|
a = _login(client, "13800003006")
|
|
b = _login(client, "13800003007")
|
|
_bind(client, b, _my_code(client, a))
|
|
|
|
_report_compare(client, b, "trace-fail-1", status="failed")
|
|
assert _invite_cash("13800003006") == 0
|
|
|
|
|
|
def test_compare_reward_isolated_from_coin_cash(client) -> None:
|
|
"""账户隔离:邀请奖励金进 invite_cash,不串 cash_balance_cents;流水落 invite_cash_transaction。"""
|
|
a = _login(client, "13800003008")
|
|
b = _login(client, "13800003009")
|
|
_bind(client, b, _my_code(client, a))
|
|
_report_compare(client, b, "trace-iso-1")
|
|
|
|
with SessionLocal() as db:
|
|
ua = get_user_by_phone(db, "13800003008")
|
|
acc = db.get(CoinAccount, ua.id)
|
|
assert acc.invite_cash_balance_cents == INVITE_COMPARE_REWARD_CENTS # 奖励金到账
|
|
assert acc.cash_balance_cents == 0 # 没串进金币现金
|
|
txns = db.execute(
|
|
select(InviteCashTransaction).where(
|
|
InviteCashTransaction.user_id == ua.id,
|
|
InviteCashTransaction.biz_type == "invite_reward",
|
|
)
|
|
).scalars().all()
|
|
assert len(txns) == 1
|
|
assert txns[0].amount_cents == INVITE_COMPARE_REWARD_CENTS
|