diff --git a/app/core/rewards.py b/app/core/rewards.py index 842f0ae..f0bc598 100644 --- a/app/core/rewards.py +++ b/app/core/rewards.py @@ -26,6 +26,16 @@ SIGNIN_REWARDS: tuple[int, ...] = ( SIGNIN_CYCLE_LEN: int = len(SIGNIN_REWARDS) +# ===== 信息流广告「按会话聚合」的 biz_type ===== +# 比价 / 领券等候期看的信息流广告,每条各写一条 coin_transaction;这两类在「金币变动记录」 +# 里按 trace_id 聚合成一条展示(见 repositories/wallet.list_coin_transactions)。其余类型 +# (reward_video / guide_video / 通用 feed_ad_reward / signin / task_* 等)不聚合。 +FEED_AD_SESSION_BIZ_TYPES: tuple[str, str] = ( + "feed_ad_reward_comparison", + "feed_ad_reward_coupon", +) + + def signin_reward(cycle_day: int) -> int: """cycle_day 取值 1..SIGNIN_CYCLE_LEN。""" return SIGNIN_REWARDS[cycle_day - 1] diff --git a/app/models/wallet.py b/app/models/wallet.py index dcdff4a..f5c22b1 100644 --- a/app/models/wallet.py +++ b/app/models/wallet.py @@ -84,6 +84,9 @@ class CoinTransaction(Base): # 关联业务 id(签到日期、任务 key 等),可空 ref_id: Mapped[str | None] = mapped_column(String(64), nullable=True) remark: Mapped[str | None] = mapped_column(String(128), nullable=True) + # 会话键:仅比价/领券信息流发奖(feed_ad_reward_comparison/coupon)时写入本场 trace_id, + # 金币记录列表据此把一次比价/领券的多条广告金币聚合成一条。其余类型 = NULL。 + trace_id: Mapped[str | None] = mapped_column(String(64), index=True, nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), index=True, nullable=False diff --git a/app/repositories/wallet.py b/app/repositories/wallet.py index fbaebbb..cd17981 100644 --- a/app/repositories/wallet.py +++ b/app/repositories/wallet.py @@ -170,6 +170,7 @@ def grant_coins( biz_type: str, ref_id: str | None = None, remark: str | None = None, + trace_id: str | None = None, ) -> tuple[CoinAccount, CoinTransaction]: """金币变动入口(正数入账 / 负数出账)。更新余额 + 写流水,不 commit。 @@ -189,6 +190,7 @@ def grant_coins( biz_type=biz_type, ref_id=ref_id, remark=remark, + trace_id=trace_id, created_at=datetime.now(rewards.CN_TZ).replace(tzinfo=None), # 存北京 wall-clock(客户端原样切片显示) ) db.add(txn) diff --git a/tests/test_welfare.py b/tests/test_welfare.py index bd99334..d9024d8 100644 --- a/tests/test_welfare.py +++ b/tests/test_welfare.py @@ -384,3 +384,22 @@ def test_endpoints_require_auth(client) -> None: assert client.get("/api/v1/savings/summary").status_code == 401 assert client.get("/api/v1/savings/battle").status_code == 401 assert client.get("/api/v1/savings/records").status_code == 401 + + +def test_grant_coins_persists_trace_id(client) -> None: + """grant_coins 传 trace_id 落库;不传则为 None。""" + phone = "13800002001" + _login(client, phone) + with SessionLocal() as db: + user = get_user_by_phone(db, phone) + assert user is not None + _, txn1 = crud_wallet.grant_coins( + db, user.id, 5, biz_type="feed_ad_reward_comparison", + ref_id="evt1", remark="比价奖励", trace_id="trace-A", + ) + _, txn2 = crud_wallet.grant_coins( + db, user.id, 30, biz_type="signin", remark="每日签到奖励", + ) + db.commit() + assert txn1.trace_id == "trace-A" + assert txn2.trace_id is None