25 lines
17 KiB
JSON
25 lines
17 KiB
JSON
{"role":"user","message":{"content":[{"type":"text","text":"<user_query>\n请在仓库 /Users/ray/Documents/project/www/ray/slot-wallet 只读探索当前“派奖(win/payout)逻辑”的主实现方式,重点找:Controller入口、Logic编排、Service处理、Model落库。请返回:1) 关键文件路径列表;2) 每个文件里与派奖相关的方法名;3) 真实流程链路(从接口入参到账变落库);4) 任何与PRD不一致或风险点(若有)。不要做修改。\n</user_query>"}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"正在只读检索派奖(win/payout)相关入口与调用链。\n\n[REDACTED]"},{"type":"tool_use","name":"updateCurrentStep","input":{"current_step":"Searching win/payout code paths","final_summary":"\n\n\n\n\n\n\n","completed_subtitle":"\n\n"}},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet","pattern":"win|payout|settle|Prize|派奖","glob":"*.php","-i":true,"head_limit":80}},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet","pattern":"(round|slots).*win|win.*slot|WinService|Settlement","glob":"*.php","-i":true,"head_limit":60}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/controller","pattern":"function\\s+win|SCENE_WIN|WalletWinRequestDTO|WalletSettleRequestDTO","glob":"*.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/service/wallet/WinService.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/logic/WalletLogic.php","offset":600,"limit":400}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Glob","input":{"target_directory":"/Users/ray/Documents/project/www/ray/slot-wallet","glob_pattern":"**/Wallet*.php"}},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api","pattern":"->win\\(|win\\(|WalletLogic","glob":"*.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/controller/WalletController.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/dto/request/wallet/WalletUpdateRequestDTO.php"}},{"type":"tool_use","name":"Read","input":{"limit":280,"offset":240,"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/model/multi/WalletAccountModel.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/logic/WalletLogic.php","limit":200}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/validator/Wallet2Validator.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet","pattern":"WalletWinRequestDTO"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/model/multi/WalletBetFundingModel.php","limit":150}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/model/multi/WalletFundLotModel.php","limit":280}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/controller","pattern":"->inc\\(|function\\s+inc\\b"}},{"type":"tool_use","name":"Read","input":{"limit":220,"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/service/wallet/BetService.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet","pattern":"walletLogic.*inc|->run\\(|WalletLogic::","glob":"*.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/logic/WalletLogic.php","offset":194,"limit":200}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/logic/WalletLogic.php","pattern":"function bet\\(|BetService"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/logic/WalletLogic.php","limit":110,"offset":480}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet","pattern":"->minus\\(|\\bminus\\(\\)","glob":"*.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet","pattern":"WalletIncRequestDTO|function inc\\(|->inc\\(","glob":"*.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet","pattern":"WalletLogic.*inc|'inc'\\s*=>"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/api/logic/WalletLogic.php","pattern":"win|WIN|Task|wager|Wager","glob":"*.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/service/WalletService.php","limit":50}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/model/multi/WalletLogModel.php","limit":120}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/doc/wallet.md","pattern":"派奖|win|最终结算|Final"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet","pattern":"FinalSettled|wallet_round|PayoutEvent|round_event"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"glob":"*.php","path":"/Users/ray/Documents/project/www/ray/slot-wallet","pattern":"game_round|GameRound"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/doc/win.md","limit":120}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/doc/win.md","offset":120}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/README.md","pattern":"update|wallet","head_limit":40}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/ray/slot-wallet/README.md","limit":65,"offset":38}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"limit":80,"path":"/Users/ray/Documents/project/www/ray/slot-wallet/app/service/WalletLogService.php"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"updateCurrentStep","input":{"completed_subtitle":"Mapped win payout call chain and files\n","current_step":"\n","final_summary":"派奖入口为 `WalletController::update`,`type=win` 时由 `WalletLogic::win` 事务内调用 `WinService::execute`,按 `wallet_bet_funding` 比例分配后进聚合账户与 Lot,写 `wallet_log`。PRD/`doc/win.md` 中的 `wallet_game_round` / `wallet_game_round_event` 及“多次派奖仅记事件”在 PHP 中未见实现;校验未强制 win 必须带 `round_id` 但服务端会报错。遗留的 `WalletLogic::inc()` 内 Redis 按比例派奖分支对当前控制器路径基本不可达。\n\n"}}]}}
|
||
{"role":"assistant","message":{"content":[{"type":"text","text":"## 1) 关键文件路径(绝对路径)\n\n| 角色 | 路径 |\n|------|------|\n| Controller 入口 | `/Users/ray/Documents/project/www/ray/slot-wallet/app/api/controller/WalletController.php` |\n| 校验(`update` 场景) | `/Users/ray/Documents/project/www/ray/slot-wallet/app/validator/Wallet2Validator.php` |\n| 请求 DTO | `/Users/ray/Documents/project/www/ray/slot-wallet/app/api/dto/request/wallet/WalletUpdateRequestDTO.php` |\n| Logic 编排 | `/Users/ray/Documents/project/www/ray/slot-wallet/app/api/logic/WalletLogic.php` |\n| 派奖领域服务 | `/Users/ray/Documents/project/www/ray/slot-wallet/app/service/wallet/WinService.php` |\n| 下注写 funding(派奖前置) | `/Users/ray/Documents/project/www/ray/slot-wallet/app/service/wallet/BetService.php` |\n| 聚合账户 DB | `/Users/ray/Documents/project/www/ray/slot-wallet/app/model/multi/WalletAccountModel.php` |\n| funding 表 | `/Users/ray/Documents/project/www/ray/slot-wallet/app/model/multi/WalletBetFundingModel.php` |\n| Lot 表 | `/Users/ray/Documents/project/www/ray/slot-wallet/app/model/multi/WalletFundLotModel.php` |\n| 幂等流水查询 / 常量 | `/Users/ray/Documents/project/www/ray/slot-wallet/app/model/multi/WalletLogModel.php` |\n| 流水写入 | `/Users/ray/Documents/project/www/ray/slot-wallet/app/service/WalletLogService.php` |\n| 薄封装:`incWinBalance` | `/Users/ray/Documents/project/www/ray/slot-wallet/app/service/WalletService.php` |\n\n补充:`WalletWinRequestDTO` 仅在定义文件中出现,未被引用;`/Users/ray/Documents/project/www/ray/slot-wallet/app/api/dto/request/WalletWinRequestDTO.php`。\n\n---\n\n## 2) 各文件与「派奖」相关的方法(按层)\n\n**`WalletController.php`**:`update(Request $request)` — 唯一走 `WalletLogic::run` 的入口。\n\n**`Wallet2Validator.php`**:`checkFeeAndBonus`(允许 `win` 且 `fee=0`、`bonus=0`)、`checkType`(含 `win`)。\n\n**`WalletUpdateRequestDTO.php`**:`type`、`fee`、`biz_id`、`round_id`、`currency`、`uid`、`trace_id` 等字段承载派奖入参。\n\n**`WalletLogic.php`**:`run()` → `ACTION_METHOD_MAP` 中 `win` → `win()`;`win()` 内幂等与事务;遗留 `inc()`、`getWinAllocationByRound()`、`cacheBetSplitByRound()`(与旧 Redis 拆单逻辑有关,见风险)。\n\n**`WinService.php`**:`execute`、`allocatePayout`、`finalizeLotAfterSettlement`、`reloadLockedWallet`、`writeWalletLog`、`buildWinRemark`、`indexLotsById`。\n\n**`BetService.php`**:`execute()` 内 `insertFundingRows()` 写入 `wallet_bet_funding`,为 Round 最终派奖提供事实数据。\n\n**`WalletAccountModel.php`**:`lockWallet`、`incWinBalance`、`moveBonusToWithdraw`、`moveDepositToWithdraw`(均在派奖/Lot 终态链路中可能被调用)。\n\n**`WalletBetFundingModel.php`**:`lockUnallocatedFundingByRound`、`markFundingFinalAllocated`、`countUnallocatedFundingByLot`。\n\n**`WalletFundLotModel.php`**:`lockLotsByIds`、`addPayoutToRemaining`、`completeLot`、`updateLotStatus`(等与派奖回流、Bonus/Deposit 终态相关)。\n\n**`WalletLogModel.php`**:`findByBizIdAndType`(幂等);常量 `BIZ_TYPE_WIN`、`BIZ_TYPE_BONUS_CONVERTED`、`BIZ_TYPE_DEPOSIT_UNLOCKED`、`BIZ_TYPE_BONUS_PLAYED_OUT` 等。\n\n**`WalletLogService.php`**:`create()` → `WalletLogModel::insertData`。\n\n**`WalletService.php`**:`win()` → `WalletAccountModel::incWinBalance`(主要被遗留 `WalletLogic::inc()` 分支使用)。\n\n---\n\n## 3) 真实流程链路(接口 → 账变落库)\n\n1. **HTTP**:`WalletController::update` 收 POST,`Wallet2Validator::SCENE_UPDATE` 校验后构造 `WalletUpdateRequestDTO`。Webman 常规路径为 **`/wallet/update`**(`WalletController` + `update` 方法)。\n2. **分发**:`WalletLogic::run` 根据 `type === 'win'` 调用 **`WalletLogic::win()`**。\n3. **事务**:`win()` 内 `WalletAccountModel::startTrans`,`lockWallet` 锁住聚合账户行。\n4. **幂等**:`WalletLogModel::findByBizIdAndType(biz_id, BIZ_TYPE_WIN)` 已存在则 rollback 并返回当前余额形态的 `WalletEntity`(不写第二笔)。\n5. **核心派奖**:`WinService::execute($requestDTO, $wallet)` \n - 校验:`round_id` 非空;`fee`(总派奖)非负(代码注释写明 **fee 为本局总派奖**)。 \n - **`wallet_bet_funding`**:`lockUnallocatedFundingByRound` 锁定该局 `round_id` 下未 Final 分配的 funding(`BetPlaced`)。 \n - **分配**:`allocatePayout` 按各 funding `bet_amount` 占该局总下注额比例拆分 `fee`,整数:先 `floor`,余数按 **出资金额从大到小、相同则 funding id 升序**补 1(与 `doc/win.md` 5.4 叙述一致)。 \n - **写 funding**:对每条 funding `markFundingFinalAllocated`(`allocated_payout_amount`、`FinalAllocated`)。 \n - **聚合入账**:汇总 bonus/deposit/withdraw 三类归属后,`WalletAccountModel::incWinBalance` 更新 `deposit_balance` / `frozen_bonus` / `withdraw_balance` 与 `version`(仅在 `fee > 0` 时入账桶)。 \n - **Lot 回流**:对每个涉及 Bonus/Deposit Lot 的派奖,`addPayoutToRemaining` 增加 `remaining_amount`。 \n - **Lot 终态**:再次锁定相关 Lot,`finalizeLotAfterSettlement`——在无未结案 funding 时,按流水与剩余金额做 Bonus→可提现、`PlayedOut`、`Deposit` 解锁等,并 **`writeWalletLog`** 写入非 `win` 的扩展流水类型(转化/解锁等)。\n6. **主派奖流水**:回到 `WalletLogic::win`,`addLog(..., BIZ_TYPE_WIN, ...)`,`WalletLogService::create` 落 **`wallet_log`**,`remark` 为含 `round_id`、三类桶汇总与 allocations 的 JSON(`WinService::buildWinRemark`)。 \n7. **提交与副作用**:`commit`;`sendConsoleBus('win', fee)`;`run` 末尾删钱包缓存。\n\n**前置依赖**:该局必须先有 **`BetService::execute` **`wallet_bet_funding`**(由 `WalletLogic::bet` 编排)。派奖与下注是 **`/wallet/update` 不同 `type` 的两次调用**,各自事务。\n\n---\n\n## 4) 与 PRD / `doc/win.md` 的差异与风险(基于仓库只读)\n\n- **`wallet_game_round` / `wallet_game_round_event` 未见 PHP 实现**(全仓无 `game_round` 模型或表访问)。PRD/`doc/win.md` 要求在 Settling 阶段按事件记账、Round 汇总与 **`FinalSettled`** 标记;当前实现是 **单笔 `win` 请求携带 Round 总派奖 `fee` 并完成 funding 分配与 Lot 处理**,等价于「最终结算一步到位」,**缺失中间多次派奖的独立持久化时点**,对账仅靠外部系统或单靠 `biz_id`/流水是否足够需业务确认。\n- **校验不对称**:`Wallet2Validator` 只强制 **`bet`** 必填 `round_id`,**未强制 `win` 必填**;但 `WinService::execute` 要求 `round_id` 非空,否则抛错。易出现 **校验通过、业务失败**(参数错误暴露在 Logic/Service)。\n- **`WalletLogic::inc()` 中 `type === win` 分支**:仍使用 **Redis 缓存的下注拆单比例**(`getWinAllocationByRound`)+ `WalletService::win`,**不读 `wallet_bet_funding`**。当前 **`WalletController` 未调用 `inc()`**,该路径对 HTTP 主线基本不可达,但与 PRD「以 funding 为准」并存时,若将来有 MQ/内部入口误调 **`inc`**,会产生 **与主线 WinService 语义不一致的高风险**。 \n- **`doc/win.md` 6.2 PlayedOut「无关联未结算 Round」**:实现侧用 **`countUnallocatedFundingByLot`**(该 Lot 上是否仍有未 Final 分配的 funding)作为近似条件,一般情况下合理;若业务上存在 **不落在 funding/lot_id 语义里的 Round 关联**,需再核对。\n- **审计追溯**:win 流水 `biz_id` 由调用方提供;Lot 衍生流水 `remark` 中含 `lot_id`、`round_id`;与 PRD「流水可追溯 `biz_id` / `lot_id` / `round_id`」整体方向一致,但 **无独立 Round 事件表时**,多次派奖过程在时间序上无法在钱包库内重演。\n\n以上为只读梳理结论;若要与 PRD 完全对齐,`doc/` 已提示的差异(Round 事件表、`FinalSettled` 状态机等)需在实现或文档中显式收口。\n\n[REDACTED]"}]}} |