Files
cursor/plans/is_end派奖结算改造_14ce4dc5.plan.md
ray zhou f71a5c59af ok
2026-05-29 11:21:40 +08:00

78 lines
4.1 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: is_end派奖结算改造
overview: 基于现有 BetFunding/WinService 实现,新增 is_end 分支:中间派奖仅累计不入账,结束派奖统一按 Round Final Settlement 入账;并对中间派奖增加 biz_id 严格幂等。
todos:
- id: dto-validator-is-end
content: 扩展 DTO 与校验器,支持 is_end 并强制 win 场景 round_id 校验
status: pending
- id: redis-win-keys
content: 新增 pending/dedupe Redis key 生成方法与 TTL 约定
status: pending
- id: logic-win-branching
content: 在 WalletLogic::win 中实现 is_end=0 累计与 is_end=1 最终结算分支
status: pending
- id: idempotency-regression
content: 补充关键回归场景说明并验证与现有幂等不冲突
status: pending
isProject: false
---
# is_end 驱动的派奖结算改造计划
## 目标
`win` 接口支持第三方 `is_end` 语义:
- `is_end=0`:仅记录/累计本局派奖,不做钱包入账、不做 Lot 终态收敛
- `is_end=1`:将本次派奖 + 已累计派奖合并后,执行一次 Final Settlement现有 `WinService::execute`
## 现状结论(基于代码)
- 入口路由在 [app/api/logic/WalletLogic.php](app/api/logic/WalletLogic.php) 的 `type=win -> win()`
- Final Settlement 主流程在 [app/service/wallet/WinService.php](app/service/wallet/WinService.php)。
- 当前 `win` 默认即 Final Settlement不区分中间派奖事件。
- 下注资金事实表在 [app/model/multi/WalletBetFundingModel.php](app/model/multi/WalletBetFundingModel.php)。
## 实现方案(按你选择)
### 1) 入参扩展与校验
- 在 [app/api/dto/request/wallet/WalletUpdateRequestDTO.php](app/api/dto/request/wallet/WalletUpdateRequestDTO.php) 增加字段:`is_end`(默认 `1`,仅允许 `0|1`)。
- 在 [app/validator/Wallet2Validator.php](app/validator/Wallet2Validator.php)
- 增加 `is_end` 校验规则(整数且取值 `0/1`)。
-`win` 也纳入 `round_id` 必传校验(当前仅 bet 必传)。
### 2) Redis Key 设计
- 在 [app/service/RedisKeyManagerService.php](app/service/RedisKeyManagerService.php) 新增两个 key 生成器:
- `wallet:win:pending:{uid}:{currency}:{round_id}`:累计未结算派奖金额
- `wallet:win:dedupe:{uid}:{currency}:{round_id}:{biz_id}`:中间派奖幂等标记
- 过期策略建议:`pending` 48h`dedupe` 72h与重放窗口对齐
### 3) win 主流程分支
- 修改 [app/api/logic/WalletLogic.php](app/api/logic/WalletLogic.php) 的 `win()`
- `is_end=0`
- 命中 dedupe key 则直接返回当前钱包(幂等)
- 未命中则将 `fee` 累加到 pending key写 dedupe key返回当前钱包不写 `BIZ_TYPE_WIN` 流水)
- `is_end=1`
- 读取 pending 累计并与本次 `fee` 合并为 `finalWinAmount`
-`finalWinAmount` 调用现有 `WinService::execute`
- 事务提交后清理 pending key失败不清
### 4) 幂等与一致性
- `is_end=1` 继续沿用现有 `wallet_log(uid,biz_id,biz_type=win)` 幂等。
- `is_end=0` 使用 Redis dedupe key 防重,避免重复累计。
-`is_end=1` 无待分配 funding保持当前行为报错便于暴露上游时序问题。
### 5) 兼容与回归
- 默认 `is_end=1`,兼容未传该字段的旧调用。
- 回归场景:
- 单次结算(只发 `is_end=1`
- 多次派奖(多条 `is_end=0` + 一条 `is_end=1`
- `is_end=0` 重放同 biz_id 不重复累计
- `is_end=1` 重放同 biz_id 不重复入账
- `is_end=1` 失败后 pending 不丢失
## 关键改动文件
- [app/api/dto/request/wallet/WalletUpdateRequestDTO.php](app/api/dto/request/wallet/WalletUpdateRequestDTO.php)
- [app/validator/Wallet2Validator.php](app/validator/Wallet2Validator.php)
- [app/service/RedisKeyManagerService.php](app/service/RedisKeyManagerService.php)
- [app/api/logic/WalletLogic.php](app/api/logic/WalletLogic.php)
## 风险与边界
- 该方案不新增 `wallet_game_round` / `wallet_game_round_event` 持久化表;中间派奖仅 Redis 暂存,审计粒度弱于 DB 事件流。
- 若某局长期无 `is_end=1`pending 依赖 TTL 过期清理。后续可升级为 DB 事件表方案。