ok
This commit is contained in:
176
plans/第一档提现或保留余额_181f2d15.plan.md
Normal file
176
plans/第一档提现或保留余额_181f2d15.plan.md
Normal file
@@ -0,0 +1,176 @@
|
||||
---
|
||||
name: 第一档提现或保留余额
|
||||
overview: 为 Free Credits 第一档(定格后首笔金额)增加用户二选一:沿用现有独立提现,或新增「保留到可提现余额」(withdraw_balance、不创建打码任务)。涉及 slot_wallet 新钱包原子能力、slot_lib RPC、slot_console 新 C 端接口与档位状态同步。
|
||||
todos:
|
||||
- id: wallet-first-keep
|
||||
content: slot_wallet:WalletLogModel + WalletLogic::freeCreditsFirstCashKeep(withdraw 入账、无 createTask)+ 单测
|
||||
status: completed
|
||||
- id: slot-lib-rpc
|
||||
content: slot_lib WalletService 增加 freeCreditsFirstCashKeep RPC
|
||||
status: completed
|
||||
- id: console-keep-api
|
||||
content: slot_console:FreeCreditsLogic::keepFirstCash + Validator + Controller + 路由
|
||||
status: completed
|
||||
- id: console-tests
|
||||
content: slot_console 单测 FreeCreditsKeepFirstCashTest;必要时调整 broadcast action
|
||||
status: completed
|
||||
- id: run-phpunit
|
||||
content: php82 容器跑 console + wallet 相关单测
|
||||
status: completed
|
||||
isProject: false
|
||||
---
|
||||
|
||||
# 第一档:提现或保留到可提现余额
|
||||
|
||||
## 背景与现状
|
||||
|
||||
当前第一档(`package_type=TYPE_FIRST_CASH`)在累计充值解锁后**仅支持**走 [`WithdrawService::applyFreeCreditsFirstCashout`](slot_console/app/service/WithdrawService.php) → Pay 独立提现(`bizType=free_credit_first_cashout`),**不经过钱包余额**(需求文档 §15.3)。
|
||||
|
||||
后续释放档走 [`FreeCreditsLogic::claim`](slot_console/app/api/logic/FreeCreditsLogic.php) → [`WalletLogic::freeCreditsClaim`](slot_wallet/app/api/logic/WalletLogic.php):入账 **deposit_balance** 并 **创建 Y1 打码任务**。
|
||||
|
||||
新需求:第一档金额用户可二选一:
|
||||
|
||||
| 选项 | 行为 |
|
||||
| --- | --- |
|
||||
| **Withdraw** | 保持现有 `/api/withdraw/apply` + `package_id` |
|
||||
| **Keep to balance** | 入账 **withdraw_balance**,**不** `createTask`,金额立即可参与普通提现规则(无其它未完成打码任务时) |
|
||||
|
||||
已确认:保留余额入账 **withdraw_balance**(非 deposit)。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
firstReady[第一档 status=ready]
|
||||
firstReady --> withdrawPath["POST /api/withdraw/apply"]
|
||||
firstReady --> keepPath["POST /api/free-credits/keep-first-cash"]
|
||||
withdrawPath --> payOrder[Pay 独立提现单]
|
||||
payOrder --> busCallback[EventBus 提现结果]
|
||||
busCallback --> pkgDone[package completed]
|
||||
keepPath --> walletKeep[wallet freeCreditsFirstCashKeep]
|
||||
walletKeep --> pkgDone
|
||||
pkgDone --> playerDone[player STATUS_FIRST_CASH_DONE]
|
||||
```
|
||||
|
||||
## 目标契约
|
||||
|
||||
### 新接口(slot_console)
|
||||
|
||||
- **路径**:`POST /api/free-credits/keep-first-cash`(与现有 `claim` 命名风格一致)
|
||||
- **入参**:`package_id`(必填,`free_credits_package.id`,须为第一档且 `status=ready`)
|
||||
- **成功**:`data` 结构同 `status()` / `claim`(`buildStatus`)
|
||||
- **幂等**:`bizId = free_credits_first_keep:{packageId}`;重复请求不重复入账
|
||||
- **互斥**:同一第一档 `processing/completed` 后不可再提现或 keep;提现处理中不可 keep
|
||||
|
||||
### 档位与玩家状态(与提现成功对齐)
|
||||
|
||||
完成后与 [`handleFirstCashoutResult(success)`](slot_console/app/api/logic/FreeCreditsLogic.php) 一致:
|
||||
|
||||
- package → `STATUS_COMPLETED`,写 `completed_time`,`claim_biz_id` 存幂等键(复用字段,无需改表)
|
||||
- player → `STATUS_FIRST_CASH_DONE`
|
||||
- 调用 `refreshPlayerCompletion`
|
||||
- 首页状态条关闭逻辑与「第一档提现成功」相同(C 端仍用 `status` / packages[0] completed)
|
||||
|
||||
### 钱包(slot_wallet)
|
||||
|
||||
新增 **`freeCreditsFirstCashKeep`**(`WalletLogic::run` 按 `type` 分发):
|
||||
|
||||
- `inc(withdraw=fee, deposit=0, bonus=0)` 增加 **withdraw_balance**
|
||||
- **不**调用 `createTask`
|
||||
- 流水:`BIZ_TYPE_FREE_CREDITS_FIRST_KEEP = 'freeCreditsFirstCashKeep'`,`WALLET_TYPE_GIFT`(与 freeze/claim 一致)
|
||||
- 事务内完成入账 + `addLog`;成功后 `sendConsoleBus`(可选,用于统计/通知,类型建议 `freeCreditsFirstCashKeep`)
|
||||
|
||||
对比现有实现:
|
||||
|
||||
| 能力 | 入账 | 打码任务 |
|
||||
| --- | --- | --- |
|
||||
| `freeCreditsClaim`(后续档) | deposit | Y1 `createTask` |
|
||||
| **`freeCreditsFirstCashKeep`(新)** | **withdraw** | **无** |
|
||||
|
||||
### slot_lib
|
||||
|
||||
[`WalletService`](slot_lib/src/services/WalletService.php) 增加常量与方法:
|
||||
|
||||
```php
|
||||
const WALLET_TYPE_FREE_CREDITS_FIRST_KEEP = 'freeCreditsFirstCashKeep';
|
||||
public function freeCreditsFirstCashKeep($amount, $bizId = ''): Wallet
|
||||
```
|
||||
|
||||
## 实现步骤
|
||||
|
||||
### 1. slot_wallet
|
||||
|
||||
| 文件 | 改动 |
|
||||
| --- | --- |
|
||||
| [`WalletLogModel.php`](slot_wallet/app/model/multi/WalletLogModel.php) | `BIZ_TYPE_FREE_CREDITS_FIRST_KEEP` |
|
||||
| [`WalletLogic.php`](slot_wallet/app/api/logic/WalletLogic.php) | `freeCreditsFirstCashKeep()`:镜像 `freeCreditsClaim` 事务结构,改为 `inc(fee,0,0)`,**删除** `createTask` 调用 |
|
||||
| 单测 | 新增 `WalletFreeCreditsFirstKeepTest`(或扩展现有 wallet 单测):断言 withdraw 增加、无 task 创建(可 mock `createTask` 不被调用) |
|
||||
|
||||
### 2. slot_lib
|
||||
|
||||
- [`WalletService.php`](slot_lib/src/services/WalletService.php):常量 + `freeCreditsFirstCashKeep($amount, $bizId)`
|
||||
|
||||
### 3. slot_console — Logic
|
||||
|
||||
[`FreeCreditsLogic.php`](slot_console/app/api/logic/FreeCreditsLogic.php) 新增 `keepFirstCash(int $uid, int $packageId): array`:
|
||||
|
||||
1. `assertEligibleParticipant`
|
||||
2. 查询 package:`uid`、`TYPE_FIRST_CASH`、`STATUS_READY`
|
||||
3. `bizId = 'free_credits_first_keep:' . $packageId`
|
||||
4. package → `STATUS_PROCESSING`,写 `claim_biz_id`
|
||||
5. `walletService->freeCreditsFirstCashKeep($package->amount_qf, $bizId)`
|
||||
6. 成功 → package `COMPLETED` + 时间戳;player `STATUS_FIRST_CASH_DONE`;`refreshPlayerCompletion`
|
||||
7. 失败 → package 回滚 `READY`(同 `claim`)
|
||||
8. 返回 `buildStatus`
|
||||
|
||||
**不**改 `advanceByRecharge` / 定格冻结逻辑。
|
||||
|
||||
### 4. slot_console — API 层
|
||||
|
||||
| 文件 | 改动 |
|
||||
| --- | --- |
|
||||
| [`FreeCreditsValidator.php`](slot_console/app/api/validator/FreeCreditsValidator.php) | `SCENE_KEEP_FIRST_CASH`:`package_id` require\|integer |
|
||||
| [`FreeCreditsController.php`](slot_console/app/api/controller/FreeCreditsController.php) | `keepFirstCash()` + PHPDoc;类注释补充第二路径 |
|
||||
| 路由配置 | 注册 `POST /api/free-credits/keep-first-cash`(查项目现有 `route` / `config` 中 `free-credits` 注册方式,与 `claim` 并列) |
|
||||
|
||||
### 5. 广播 / 统计(小改)
|
||||
|
||||
- [`buildBroadcastList`](slot_console/app/api/logic/FreeCreditsLogic.php):第一档 completed 若走 keep,广播 `action` 可新增 `keep`(或复用 `claim`);与产品确认文案前可先 `keep`
|
||||
- [`FreeCreditsStatsLogic`](slot_console/app/innerapi/logic/FreeCreditsStatsLogic.php):`first_cashout_*` 按「第一档 completed」统计,**keep 与 withdraw 均计入**(无需区分,除非运营后续要拆指标)
|
||||
|
||||
### 6. 单测(slot_console)
|
||||
|
||||
| 文件 | 内容 |
|
||||
| --- | --- |
|
||||
| 新增 `FreeCreditsKeepFirstCashTest` | harness 注入 mock `WalletService`;断言状态迁移、幂等、非 ready 抛错 |
|
||||
| 可选集成测 | keep 后 package completed + player `FIRST_CASH_DONE` |
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
docker exec -w /app/www/slot/slot_console php82 ./vendor/bin/phpunit tests/Unit/FreeCreditsKeepFirstCashTest.php
|
||||
docker exec -w /app/www/slot/slot_wallet php82 ./vendor/bin/phpunit tests/Unit/WalletFreeCreditsFirstKeepTest.php
|
||||
```
|
||||
|
||||
## C 端约定(供联调,本次可不改 PWA)
|
||||
|
||||
第一档 `packages[0].status === 1` 时展示两个入口:
|
||||
|
||||
- **Withdraw** → 现有 `POST /api/withdraw/apply` + `package_id`
|
||||
- **Keep to Balance** → `POST /api/free-credits/keep-first-cash` + `package_id`
|
||||
|
||||
完成后 `packages[0].status === 3`,与提现成功 UI 一致(按钮隐藏 / 成功态)。
|
||||
|
||||
## 不在本次范围
|
||||
|
||||
- slot_pwa / gateway 前端页面与文案
|
||||
- 需求文档 §10–11 全文修订(可后续补「Add to Balance」分支)
|
||||
- 修改后续档 `claim` 的打码规则
|
||||
- 第一档金额改由后台配置动态展示(仍从 `packages[0].amount` 读取)
|
||||
|
||||
## 验收清单
|
||||
|
||||
1. 第一档 ready:keep 成功 → withdraw_balance 增加对应千分位,**无**新 WagerTask
|
||||
2. 同一 package 重复 keep:幂等,不重复加钱
|
||||
3. keep 成功后:package/player 状态与提现成功一致;`status` 接口 packages[0] 为 completed
|
||||
4. 第一档 processing(提现中):keep 拒绝
|
||||
5. 第一档 completed:withdraw / keep 均拒绝
|
||||
6. 相关单测通过
|
||||
Reference in New Issue
Block a user