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,181 +0,0 @@
---
name: firstCashout 合并代码评审
overview: 你对「merge post + 统一 WithdrawService::apply」的改法方向正确但当前 WithdrawService 在 package_id>0 时仍执行 checkInfo/手续费/黑规则,且 Pay 失败无回滚,会导致第一档提现不可用或卡在 processing。
todos:
- id: fc-early-return
content: WithdrawService::apply 中 package_id>0 走独立 applyFreeCreditsFirstCashout 并 early return
status: completed
- id: skip-checkinfo-fc
content: FC 分支跳过 checkInfo、getAmountAndFee、黑规则或产品确认保留项
status: completed
- id: pay-fail-rollback
content: Pay apply 失败时 handleFirstCashoutResult 回滚 processing
status: completed
- id: fc-withdrawal-info
content: FC 使用 package amount_qf、fee=0、auditType=2 组 WithdrawalInfo
status: completed
isProject: false
---
# firstCashout 合并改动 — 代码评审
## 你的改动(理解正确)
```mermaid
sequenceDiagram
participant Ctrl as WithdrawController
participant FC as FreeCreditsLogic
participant WS as WithdrawService
participant Pay as slot_pay
Ctrl->>FC: mergeFirstCashoutIntoPost
Note over FC: amount + bizType + package_id
Ctrl->>WS: apply(DTO)
WS->>FC: firstCashout(uid, packageId, orderId)
Note over FC: markFirstCashoutProcessing
WS->>Pay: apply(WithdrawalInfo)
```
- [`WithdrawController::apply`](slot_console/app/api/controller/WithdrawController.php):有 `package_id` 先 merge再**同一套** `validate($type)` — 符合预期。
- [`mergeFirstCashoutIntoPost`](slot_console/app/api/logic/FreeCreditsLogic.php):补 `amount` / `bizType` / `package_id` — 符合预期。
- [`firstCashout`](slot_console/app/api/logic/FreeCreditsLogic.php) 收窄为只 `markFirstCashoutProcessing` + 外部统一 `PayService::apply` — 思路可行。
---
## P0FC 仍会走 `checkInfo`,大概率直接失败
[`WithdrawService::apply`](slot_console/app/service/WithdrawService.php) 当前顺序:
```php
$bankInfo = $this->checkBankInfo($applyDTO);
$this->checkInfo($applyDTO->type, $applyDTO->amount); // 始终执行
// ...
if ($applyDTO->package_id > 0) {
firstCashout(...); // 永远走不到checkInfo 已抛错)
}
```
`checkInfo` 会校验**钱包可提现余额** ≥ amount[`WithdrawService.php` L333-335](slot_console/app/service/WithdrawService.php))。
Free Credits 第一档资金在**活动池**,不在普通 `withdraw` 余额里 → 典型报错 **`Insufficient balance`**。
**结论**:与需求「不进入普通钱包」冲突,第一档线上基本提不了现。
**建议**`package_id > 0`(或 `bizType === free_credit_first_cashout`)时 **跳过** `checkInfo`(及与之绑定的首提 min/max 规则)。
---
## P0Pay 失败时档位已置为 processing无回滚
你现在在 **Pay 之前** 调用 `firstCashout``markFirstCashoutProcessing`status=2
原实现是mark → `PayService::apply`**catch 时** `handleFirstCashoutResult($orderId, false)` 恢复 ready。
当前 [`WithdrawService::apply`](slot_console/app/service/WithdrawService.php) L236 调 pay **没有** try/catch 回滚 → 申请失败时 package 会一直 **processing**,用户无法重试。
**建议**
```php
if ($applyDTO->package_id > 0) {
$orderId = CommonFn::generateOrderId(4, $userTag->uid);
(new FreeCreditsLogic())->firstCashout($userTag->uid, $applyDTO->package_id, $orderId);
$withdrawalInfo->orderId = $orderId;
$withdrawalInfo->bizType = FreeCreditsLogic::BIZ_TYPE_FIRST_CASHOUT;
try {
$res = PayService::getInstance()->apply($withdrawalInfo->toArray());
return $res;
} catch (\Throwable $e) {
(new FreeCreditsLogic())->handleFirstCashoutResult($orderId, false);
throw $e;
}
}
```
FC 分支应 **early return**,不要继续走下面黑规则 + `getAmountAndFee`。)
---
## P1FC 仍走普通手续费 / 黑规则 / auditType
合并后 FC 路径仍执行:
- `getAuditType($applyDTO->amount)``BlackApiService`、提现倍数检测
- `getAmountAndFee($applyDTO->amount, $this->withdrawal)` — 可能扣手续费、按钱包余额改金额
原 [`firstCashout`](slot_console/app/api/logic/FreeCreditsLogic.php) 约定:
- `fee = 0`
- `auditType = 2`(人工审核)
- `amount = package->amount_qf`(千分位,不经手续费逻辑)
`merge` 写入的 `amount`**展示大单位**`getNumberFormat(qf)`),再经 `getAmountAndFee` 可能与 pay 侧期望的千分位不一致。
**建议**FC 分支单独组 `WithdrawalInfo`
| 字段 | FC 取值 |
|------|---------|
| amount | 从 package 读 `amount_qf`(或 merge 时额外缓存 `_amount_qf` |
| fee | 0 |
| auditType | 2 |
| bizType | `free_credit_first_cashout` |
| 黑规则 | 跳过(或产品确认是否要对 FC 也做) |
---
## P1`firstCashout` 与 `markFirstCashoutProcessing` 重复校验
[`firstCashout`](slot_console/app/api/logic/FreeCreditsLogic.php) 内再次查 `STATUS_READY` 后调用 `markFirstCashoutProcessing`,而 `markFirstCashoutProcessing` ** again** 要求 `STATUS_READY`L343
逻辑重复但无害;可简化为只调 `markFirstCashoutProcessing`,或只保留一处校验。
注意:`mergeFirstCashoutIntoPost` 已校验 ready`firstCashout` 时若并发重复提交,第二次会在 mark 阶段失败 — 符合「处理中不可重复提交」。
---
## P2行为变化需产品确认
| 项 | 原 FC | 现统一 apply |
|----|--------|----------------|
| `is_bind_name` | 不校验 | **校验**L157 |
| Redis 5s 频控 | 无 | **有** |
| 返回值 | `{order_id, amount}` | pay `apply` 原始结构 |
若 C 端依赖 `data.order_id` / `data.amount` 展示,需确认 pay 返回是否一致。
---
## 做得好的部分
- Controller 单入口 + merge post**正确**。
- 去掉独立 FC validator scene**正确**。
- [`FreeCreditsController::firstCashout`](slot_console/app/api/controller/FreeCreditsController.php) 兼容路径与主入口一致:**正确**。
- pay 层仍靠 `bizType` 跳过 `withdrawFrozen`**只要 bizType 确实传到 pay 就没问题**(当前 L184 已设)。
---
## 推荐修复结构(最小 diff
在 [`WithdrawService::apply`](slot_console/app/service/WithdrawService.php) 开头(绑卡、频控之后):
```php
if ($applyDTO->package_id > 0) {
return $this->applyFreeCreditsFirstCashout($applyDTO, $bankInfo);
}
// 原有普通提现逻辑不变
```
`applyFreeCreditsFirstCashout` 内:
1. 跳过 `checkInfo`、黑规则、`getAmountAndFee`
2. `orderId``firstCashout`mark→ 组 `WithdrawalInfo`qf amount, fee=0, auditType=2, bizType
3. try/catch pay + `handleFirstCashoutResult` 回滚
**不要**在普通流程中间用 `if ($package_id > 0) { firstCashout; }` 再接着跑普通逻辑 — 这是当前问题的根源。
---
## 验收清单
- [ ] `package_id>0` 且钱包 withdraw=0能成功提交 pay不报 Insufficient balance
- [ ] pay 申请失败package 回到 ready可再次提现
- [ ] pay 成功 + 回调package completedplayer `FIRST_CASH_DONE`
- [ ] 普通提现无 `package_id`:行为与改前一致
- [ ] `remark`/bizType 在 pay 侧仍为 `free_credit_first_cashout`,不冻结钱包