This commit is contained in:
ray zhou
2026-05-21 19:39:52 +08:00
parent 10f55e0262
commit 5d6d482efe
33 changed files with 2 additions and 3946 deletions

View File

@@ -1,78 +0,0 @@
---
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 事件表方案。