Files
cursor/plans/中间派奖余额可见化_175ab934.plan.md
ray zhou f71a5c59af ok
2026-05-29 11:21:40 +08:00

91 lines
4.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: 中间派奖余额可见化
overview: 在保持 Final Settlement 真账口径不变的前提下,让 is_end=0 中间派奖实时反映到三方读取的余额(接口返回和钱包查询)。
todos:
- id: pending-win-keys
content: 设计并接入 pending round/total 与 dedupe Redis key
status: pending
- id: win-is-end-branch
content: 实现 is_end=0 累计展示、is_end=1 合并结算与清理
status: pending
- id: wallet-query-overlay
content: 让 wallet 查询叠加 pending total 返回最新展示余额
status: pending
- id: dto-validator-update
content: 补齐 is_end DTO 与 win round_id 校验
status: pending
- id: regression-cases
content: 验证多次派奖余额可见、最终结算、幂等与失败重试场景
status: pending
isProject: false
---
# 中间派奖余额可见化is_end改造计划
## 目标
解决“多次派奖时三方读取余额不更新”的问题,同时保持 `win.md` 的核心原则:
- 真正入账、Lot 回流、转化/解锁只在 `is_end=1`Final Settlement执行
- `is_end=0` 仅做中间派奖累计与展示余额更新
## 核心思路
在 Redis 维护“待结算派奖池Pending Win并把它叠加到对外返回余额
- DB 里的 `withdraw/deposit/bonus` 仍保持真实账
- 对外给三方的余额 = 真实账 + pendingWin
这样能保证:
- 三方实时看到余额变化
- 不破坏现有 `WinService` 的 Round Final Settlement 账务逻辑
## 具体改造
### 1) 新增 Pending Win 缓存层
修改 [app/service/RedisKeyManagerService.php](app/service/RedisKeyManagerService.php):新增 key
- `wallet:win:pending:round:{uid}:{currency}:{round_id}`(每局中间派奖累计)
- `wallet:win:pending:total:{uid}:{currency}`(用户币种维度累计,供快速读余额)
- `wallet:win:dedupe:{uid}:{currency}:{round_id}:{biz_id}`(中间派奖严格幂等)
### 2) win 分支行为
修改 [app/api/logic/WalletLogic.php](app/api/logic/WalletLogic.php) 的 `win()`
- `is_end=0`
- 命中 dedupe 直接返回
- 未命中则 `INCRBY pending:round``INCRBY pending:total`
- 返回余额时把 `pending:total` 叠加到 `withdraw`(仅对外展示)
- 不调用 `WinService::execute`、不写 `BIZ_TYPE_WIN`
- `is_end=1`
- 读取 `pending:round``finalWin = fee + pendingRound`
-`finalWin` 调用现有 [app/service/wallet/WinService.php](app/service/wallet/WinService.php)
- 成功后清理 `pending:round` 并从 `pending:total` 扣除对应值
- 返回余额按真实账(此时 pending 已回收)
### 3) 钱包查询返回也要可见化
修改 [app/api/logic/WalletLogic.php](app/api/logic/WalletLogic.php) 的 `query()` 返回:
-`pending:total` 叠加到返回字段 `w/withdraw`
- 这样第三方无论读 `win` 返回还是调用 `wallet` 查询,都看到“最新展示余额”
### 4) DTO/校验补齐
- 在 [app/api/dto/request/wallet/WalletUpdateRequestDTO.php](app/api/dto/request/wallet/WalletUpdateRequestDTO.php) 增加 `is_end`(默认 1
- 在 [app/validator/Wallet2Validator.php](app/validator/Wallet2Validator.php) 增加:
- `is_end` 仅允许 `0/1`
- `win` 场景强制 `round_id` 必传
## 一致性与幂等
- `is_end=0`Redis dedupebiz_id 级)防重复累计
- `is_end=1`:延续现有 `wallet_log(uid,biz_id,biz_type=win)` 幂等
- 若 Final 失败,不清 pending便于重试恢复
## 风险说明(需明确)
- 该方案是“展示余额实时、真账延后”:若上游把展示余额当可立即可下注余额,可能出现下注时余额校验不一致。
- 若你需要“中间派奖立即可下注”,则要走另一套方案(中间账临时入库 + Final 对冲重分配),改动会显著更大。
## 改动文件
- [app/service/RedisKeyManagerService.php](app/service/RedisKeyManagerService.php)
- [app/api/dto/request/wallet/WalletUpdateRequestDTO.php](app/api/dto/request/wallet/WalletUpdateRequestDTO.php)
- [app/validator/Wallet2Validator.php](app/validator/Wallet2Validator.php)
- [app/api/logic/WalletLogic.php](app/api/logic/WalletLogic.php)
## 验收场景
- 多次 `is_end=0` 后,`win` 返回余额递增
- 多次 `is_end=0` 后,`wallet` 查询余额递增
- `is_end=1` 触发后final 入账金额 = 中间累计 + 最后一笔
- 重放同一 `is_end=0` `biz_id` 不重复累计
- 重放同一 `is_end=1` `biz_id` 不重复结算