Compare commits

...

2 Commits

Author SHA1 Message Date
zzhyyyyy 3a60672f95 Merge remote-tracking branch 'origin/main' into feat/withdrawal-rewarded-ad 2026-06-24 22:18:53 +08:00
zzhyyyyy 9986a8c4f8 feat(ad): 提现看视频广告后端支持(withdrawal_ad 场景 + 开关下发)
- pangle-callback 新增 withdrawal_ad 场景:不发金币、只记一条幂等(coin=0),
  避免提现看视频被穿山甲 S2S 回调误发金币
- ad_config 新增 withdrawal_ad_enabled 开关(默认 true),贯穿 admin schema 与
  platform 下发接口,客户端拉取后用(关=直接放行提现)
- 提现广告 eCPM 复用 /ad/ecpm-report,以 ad_type=withdrawal_video 区分收益,无需 DB 迁移
2026-06-24 22:18:52 +08:00
5 changed files with 21 additions and 0 deletions
+2
View File
@@ -15,6 +15,7 @@ class AdConfigOut(BaseModel):
reward_enabled: bool
compare_ad_enabled: bool
coupon_ad_enabled: bool
withdrawal_ad_enabled: bool
class AdConfigUpdate(BaseModel):
@@ -28,3 +29,4 @@ class AdConfigUpdate(BaseModel):
reward_enabled: bool | None = None
compare_ad_enabled: bool | None = None
coupon_ad_enabled: bool | None = None
withdrawal_ad_enabled: bool | None = None
+16
View File
@@ -53,6 +53,9 @@ REASON_UNKNOWN_USER = 2 # user_id 不存在(可能伪造)
REWARD_SCENE_REWARD_VIDEO = "reward_video"
REWARD_SCENE_SIGNIN_BOOST = "signin_boost"
# 提现看视频:看完才能提现的「硬门槛」广告,**不发金币**,只记一条幂等记录(收益由 eCPM 上报口径
# ad_type="withdrawal_video" 单独统计)。故意不放进 SUPPORTED_REWARD_SCENES——它不走发币分支。
REWARD_SCENE_WITHDRAWAL_AD = "withdrawal_ad"
SUPPORTED_REWARD_SCENES = {REWARD_SCENE_REWARD_VIDEO, REWARD_SCENE_SIGNIN_BOOST}
@@ -126,6 +129,19 @@ def pangle_callback(request: Request, db: DbSession) -> PangleCallbackOut:
return PangleCallbackOut(is_verify=True, reason=REASON_OK)
try:
if reward_scene == REWARD_SCENE_WITHDRAWAL_AD:
# 提现看视频:已知合法场景,只记一条幂等记录、**不动钱包**(发不发币由 reward_scene 决定)。
# is_verify=true 让穿山甲不重试(区别于 unknown_scene 的 false)。
crud_ad.record_external_reward(
db, user_id, trans_id, coin=0, reward_scene=REWARD_SCENE_WITHDRAWAL_AD,
ad_session_id=ad_session_id, ecpm=ecpm,
reward_name=params.get("reward_name"), raw=raw[:1024],
status="withdrawal_ad",
)
logger.info(
"pangle callback withdrawal_ad user_id=%d trans_id=%s", user_id, trans_id,
)
return PangleCallbackOut(is_verify=True, reason=REASON_OK)
if reward_scene not in SUPPORTED_REWARD_SCENES:
rec = crud_ad.record_external_reward(
db, user_id, trans_id, coin=0, reward_scene=reward_scene[:32],
+1
View File
@@ -68,6 +68,7 @@ def ad_config(db: DbSession) -> AdConfigPublicOut:
reward_enabled=c["reward_enabled"],
compare_ad_enabled=c["compare_ad_enabled"],
coupon_ad_enabled=c["coupon_ad_enabled"],
withdrawal_ad_enabled=c["withdrawal_ad_enabled"],
)
+1
View File
@@ -109,6 +109,7 @@ _AD_CONFIG_DEFAULTS: dict[str, Any] = {
"reward_enabled": True, # 福利激励视频开关
"compare_ad_enabled": True, # 比价广告开关
"coupon_ad_enabled": True, # 领券广告开关
"withdrawal_ad_enabled": True, # 提现激励视频开关(关=直接放行提现,不挡用户的钱)
}
+1
View File
@@ -43,6 +43,7 @@ class AdConfigPublicOut(BaseModel):
reward_enabled: bool # 福利激励视频开关
compare_ad_enabled: bool # 比价广告开关
coupon_ad_enabled: bool # 领券广告开关
withdrawal_ad_enabled: bool # 提现激励视频开关(关=客户端直接放行提现)
class AppVersionOut(BaseModel):