first commit
This commit is contained in:
223
plans/首充定格资金修复_ac2c16c6.plan.md
Normal file
223
plans/首充定格资金修复_ac2c16c6.plan.md
Normal file
@@ -0,0 +1,223 @@
|
||||
---
|
||||
name: 首充定格资金修复
|
||||
overview: 本次仅改 slot_wallet 与 slot_console。wallet 删除 Recharge bus、首充发 free_credit_init;console 消费该事件完成定格。pay 等其它服务不在本次范围。
|
||||
todos:
|
||||
- id: wallet-remove-recharge-bus
|
||||
content: 删除 WalletLogic recharge/rechargeSign 中 sendConsoleBus('Recharge')
|
||||
status: completed
|
||||
- id: wallet-send-free-credit-init
|
||||
content: recharge + rechargeSign 首充时发送 free_credit_init(inc/改账前采 balance_before_qf)
|
||||
status: completed
|
||||
- id: wallet-remove-create-wager-first-recharge
|
||||
content: CreateWagerTask 删除 version1/version2 首充特殊打码分支,首充走普通充值打码
|
||||
status: completed
|
||||
- id: console-event-bus-handler
|
||||
content: EventBus case free_credit_init + FreeCreditInitEvent
|
||||
status: completed
|
||||
- id: console-free-credit-init-logic
|
||||
content: handleFreeCreditInit;RechargeEvent 移除首充定格,保留档位推进
|
||||
status: completed
|
||||
- id: console-safe-freeze-order
|
||||
content: freezeFirstRecharge 先 RPC 后落库;上限与幂等
|
||||
status: completed
|
||||
- id: mq-reliability
|
||||
content: free_credit_init 失败 nack/requeue(仅 console EventBus)
|
||||
status: completed
|
||||
- id: tests-and-repair
|
||||
content: wallet/console 单测与集成测;FreeCreditsFreezeDev 补偿(console)
|
||||
status: completed
|
||||
isProject: false
|
||||
---
|
||||
|
||||
# 首充定格资金操作修复方案(修订 v4)
|
||||
|
||||
## 变更范围(硬约束)
|
||||
|
||||
**本次仅编辑以下仓库/服务,不修改任何其它服务(含 slot_pay、slot_lib 等):**
|
||||
|
||||
| 在范围内 | 不在范围内 |
|
||||
|----------|------------|
|
||||
| `slot_wallet` | `slot_pay` |
|
||||
| `slot_console` | `slot_lib`、`slot_agent`、… |
|
||||
|
||||
> `Recharge` 总线消息假定由 **pay 或其它既有链路** 发送;本次不从 wallet 重复发送,也**不改 pay** 去补发。若线上 pay 未发 `Recharge`,统计/档位问题需另开 pay 任务,**不纳入本 PR**。
|
||||
|
||||
---
|
||||
|
||||
## 设计原则
|
||||
|
||||
> **情愿用户定格失败,也不能让系统亏钱。**
|
||||
|
||||
| 服务(本次) | 职责 |
|
||||
|--------------|------|
|
||||
| **slot_wallet** | 入账;首充发 **`free_credit_init`**;**删除** `Recharge` bus;**移除** `CreateWagerTask` 旧首充打码拆分 |
|
||||
| **slot_console** | 消费 `free_credit_init` → 定格扣款 + 活动落库;`RechargeEvent` **不再**做首充定格 |
|
||||
|
||||
---
|
||||
|
||||
## 目标架构
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Ext as 外部_pay等_本次不改
|
||||
participant Wallet as slot_wallet
|
||||
participant MQ as console_bus
|
||||
participant Console as slot_console
|
||||
|
||||
Ext->>Wallet: recharge / rechargeSign
|
||||
Wallet->>Wallet: 采 balance_before_qf,入账
|
||||
Wallet->>MQ: free_credit_init
|
||||
Ext->>MQ: Recharge(本次不实现)
|
||||
MQ->>Console: FreeCreditInitEvent
|
||||
Console->>Wallet: freeCreditsFreeze RPC
|
||||
Console->>Console: player/package 落库
|
||||
MQ->>Console: RechargeEvent(既有逻辑,无定格)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 实现步骤
|
||||
|
||||
### 1. slot_wallet
|
||||
|
||||
#### 1.1 删除 `Recharge` bus
|
||||
|
||||
从 [`WalletLogic::recharge()`](file:///Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php)、[`rechargeSign()`](file:///Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php) 移除:
|
||||
|
||||
```php
|
||||
$this->sendConsoleBus('Recharge', $this->requestDTO->recharge);
|
||||
```
|
||||
|
||||
保留 `sendConsoleBus('reward', ...)` 及其它非 Recharge 类型(本次不动)。
|
||||
|
||||
#### 1.2 `maybeSendFreeCreditInit()` + 扩展 `sendConsoleBus`
|
||||
|
||||
- 改账/ `inc()` **前**:`balance_before_qf`、`is_first_recharge`(`total_deposit == 0`,在 `statModel->inc` 之前判断)。
|
||||
- 改账成功后:`is_first_recharge && balance_before_qf > 0` 时发送:
|
||||
|
||||
```php
|
||||
$this->sendConsoleBus('free_credit_init', 0, [
|
||||
'balance_before_qf' => $balanceBeforeQf,
|
||||
'recharge_amount' => $this->requestDTO->recharge,
|
||||
]);
|
||||
```
|
||||
|
||||
- [`sendConsoleBus()`](file:///Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php) 增加可选参数 `array $extraData = []`。
|
||||
|
||||
#### 1.3 `recharge()` 与 `rechargeSign()` 均接入
|
||||
|
||||
签到购买 [`rechargeSign()`](file:///Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php) 与普通 [`recharge()`](file:///Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php) 使用同一套 `maybeSendFreeCreditInit()` 逻辑。
|
||||
|
||||
#### 1.4 移除 `CreateWagerTask` 旧首充打码逻辑(已废弃)
|
||||
|
||||
[`app/command/CreateWagerTask.php`](file:///Users/ray/Documents/project/www/slot/slot_wallet/app/command/CreateWagerTask.php) 在 **Free Credits 上线前** 于首充时本地拆分余额打码,与现「console 定格 + 分档释放」重复且易冲突,**本次删除**。
|
||||
|
||||
**旧逻辑位置**(条件均为 `RechargeExchangeService::total` 累计充值等于本笔 `recharge_amount`,即首充):
|
||||
|
||||
| 方法 | 行号(约) | 行为 |
|
||||
|------|-----------|------|
|
||||
| `version1()` | L87–140 | `SOURCE_TYPE_FIRST_RECHARGE` 任务 + `SOURCE_TYPE_FREE` 免打码任务 + `SOURCE_TYPE_FIRST_LEFT`「首充剩余」打码 |
|
||||
| `version2()` | L186–244 | 首充充值/赠送打码 + `SOURCE_TYPE_FIRST_LEFT`(`first_recharge_left` 系数) |
|
||||
|
||||
**与新方案关系**:
|
||||
|
||||
- 充值前免费余额 → 由 console `free_credit_init` → `freeCreditsFreeze` 扣出活动池(不再在 wallet 侧拆 `FREE` / `FIRST_LEFT` 任务)。
|
||||
- 免打码第一档 / 后续释放 → 由 console `FreeCreditsLogic` + `freeCreditsClaim` 创建 Y1(`WalletLogic::freeCreditsClaim` 内 `createTask`)。
|
||||
- 首充**本笔充值金额**的打码 → 与其它充值相同,走 `elseif ($dto->required_wager > 0)` 通用分支即可。
|
||||
|
||||
**改动要点**:
|
||||
|
||||
1. 删除 `version1` / `version2` 中整段 `if ($entity->recharge > 0 && $entity->recharge == $dto->recharge_amount) { ... }`。
|
||||
2. 首充与普通充值统一落入后续 `elseif ($dto->required_wager > 0)`(`version1` L142+、`version2` L246+)。
|
||||
3. **保留**其中对 `SOURCE_TYPE_BUY_SIGN`(购买签到解锁额度为 0)的处理——该逻辑在 `elseif` 分支内已有,无需首充专用块。
|
||||
4. 删除后确认无引用孤立的 `SOURCE_TYPE_FIRST_RECHARGE` / `SOURCE_TYPE_FIRST_LEFT` 首充专用路径(常量可保留供历史任务读)。
|
||||
|
||||
---
|
||||
|
||||
### 2. slot_console
|
||||
|
||||
#### 2.1 EventBus 注册 `free_credit_init`
|
||||
|
||||
[`EventBus::deal()`](file:///Users/ray/Documents/project/www/slot/slot_console/app/command/EventBus.php) 增加显式分支(类名不能走 default 动态加载):
|
||||
|
||||
```php
|
||||
case 'free_credit_init':
|
||||
(new FreeCreditInitEvent())->handle($busEntity);
|
||||
break;
|
||||
```
|
||||
|
||||
新建 [`app/command/event/FreeCreditInitEvent.php`](file:///Users/ray/Documents/project/www/slot/slot_console/app/command/event/FreeCreditInitEvent.php)。
|
||||
|
||||
#### 2.2 `FreeCreditsLogic::handleFreeCreditInit`
|
||||
|
||||
- 入参:`uid`、`balance_before_qf`、`wallet_amount`、`orderId`(来自 bus `data`)。
|
||||
- `frozenAmount = max(balance_before_qf, 0)`;**不以**充值后再读余额反推为主路径。
|
||||
- 活动未开启 / 已定格 → 幂等 return。
|
||||
- 调用调整后的 `freezeFirstRecharge()`。
|
||||
|
||||
#### 2.3 调整 `freezeFirstRecharge`(先扣款、后落库)
|
||||
|
||||
[`freezeFirstRecharge()`](file:///Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php):
|
||||
|
||||
1. 幂等:已有 `free_credits_freeze:{orderId}` 流水则跳过 RPC。
|
||||
2. `frozenAmount = min(事件金额, RPC 前当前可扣余额)`;≤0 不扣。
|
||||
3. **先** `freeCreditsFreeze` RPC,**后** `Db::transaction` 写 player/packages。
|
||||
4. RPC 失败 → 不落库,**抛异常**。
|
||||
|
||||
#### 2.4 `RechargeEvent` 去掉首充定格
|
||||
|
||||
[`RechargeEvent::handle()`](file:///Users/ray/Documents/project/www/slot/slot_console/app/command/event/RechargeEvent.php) **删除** L73-82 对 `handleRecharge` 的调用(首充定格改由 `free_credit_init` 触发)。
|
||||
|
||||
保留并可继续调用 **仅档位推进** 的逻辑,例如:
|
||||
|
||||
- 新增 `FreeCreditsLogic::advanceAfterRecharge($uid, $walletAmount)`,或
|
||||
- `handleRecharge` 内去掉首充 `freezeFirstRecharge` 分支,仅保留 `advanceByRecharge`(供既有 `Recharge` 消息使用)。
|
||||
|
||||
统计、黑名单、代理首充等 **RechargeEvent 现有代码不动**(本次范围外行为保持)。
|
||||
|
||||
#### 2.5 MQ 可靠性(仅 console)
|
||||
|
||||
- `FreeCreditInitEvent` / `free_credit_init`:异常上抛;`EventBus` 对该 type 失败时 **nack/requeue**(需对齐现有 consumer)。
|
||||
- `Recharge` 路径统计块仍可独立 try/catch(本次不改 pay 发消息前提)。
|
||||
|
||||
---
|
||||
|
||||
### 3. 测试(仅 wallet + console)
|
||||
|
||||
| 用例 | 位置 |
|
||||
|------|------|
|
||||
| wallet 删除 Recharge bus | slot_wallet |
|
||||
| wallet 首充发 `free_credit_init`(含 rechargeSign) | slot_wallet |
|
||||
| 首充不再走 CreateWagerTask 特殊分支 | slot_wallet CreateWagerTask |
|
||||
| `FreeCreditInitEvent` 定格成功 | slot_console 集成测 |
|
||||
| RPC 失败不落库 / 先扣后落库 / 幂等 | slot_console |
|
||||
| `RechargeEvent` 不再触发定格 | 调整 [`FreeCreditsHandleRechargeTest`](file:///Users/ray/Documents/project/www/slot/slot_console/tests/Unit/FreeCreditsHandleRechargeTest.php) 等 |
|
||||
|
||||
**不新增** pay 侧联调用例。
|
||||
|
||||
---
|
||||
|
||||
## 关键改动文件(仅此两份)
|
||||
|
||||
**slot_wallet**
|
||||
|
||||
- [`app/api/logic/WalletLogic.php`](file:///Users/ray/Documents/project/www/slot/slot_wallet/app/api/logic/WalletLogic.php)
|
||||
- [`app/command/CreateWagerTask.php`](file:///Users/ray/Documents/project/www/slot/slot_wallet/app/command/CreateWagerTask.php)
|
||||
|
||||
**slot_console**
|
||||
|
||||
- [`app/command/EventBus.php`](file:///Users/ray/Documents/project/www/slot/slot_console/app/command/EventBus.php)
|
||||
- `app/command/event/FreeCreditInitEvent.php`(新建)
|
||||
- [`app/api/logic/FreeCreditsLogic.php`](file:///Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php)
|
||||
- [`app/command/event/RechargeEvent.php`](file:///Users/ray/Documents/project/www/slot/slot_console/app/command/event/RechargeEvent.php)
|
||||
- 相关 tests(console 仓内)
|
||||
|
||||
---
|
||||
|
||||
## 验收标准(本 PR)
|
||||
|
||||
- **wallet**:`recharge` / `rechargeSign` 不再发送 `type=Recharge`;首充且 inc 前有免费余额时发送 `free_credit_init`,`balance_before_qf` 正确。
|
||||
- **wallet**:首充不再触发 `CreateWagerTask` 的 `FIRST_RECHARGE` / `FREE` / `FIRST_LEFT` 拆分,仅按本笔充值/赠送金额走通用打码任务。
|
||||
- **console**:收到 `free_credit_init` 后完成定格扣款与落库;扣款 ≤ 事件金额且 ≤ 可扣余额;幂等。
|
||||
- **console**:`RechargeEvent` 不再执行首充定格;已定格用户经 `Recharge` 仍可 `advanceByRecharge`(依赖外部 pay 发消息,**本 PR 不验证 pay**)。
|
||||
- **范围**:`git diff` 仅涉及 `slot_wallet`、`slot_console` 路径。
|
||||
Reference in New Issue
Block a user