8.4 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 第一档提现审核拒绝 | 补齐管理后台「拒绝退钱/拒绝扣钱」对 Free Credits 第一档独立提现(free_credit_first_cashout)的处理:Pay 侧识别业务类型、避免误动钱包,并通过已有 Console 总线回调恢复档位状态。 |
|
false |
第一档提现:后台审核拒绝处理
问题确认
管理后台 slot_admin_vue/.../withdrawal/index.vue 点「拒绝退钱」(audit_status=2) / 「拒绝扣钱」(audit_status=3) → WithdrawalOrderController::audit → PayService::withdrawalAudit → WithdrawalOrderEntity::audit。
当前 audit() 一律对普通提现调用 withdrawFail / withdrawDone,不通知 slot_console 的 FreeCreditsLogic::handleFirstCashoutResult。
第一档提现(FreeCreditsLogic::applyFirstCashoutWithdraw,bizType=free_credit_first_cashout)在提交时已 markFirstCashoutProcessing,审核拒绝后档位会卡在 processing,C 端无法再次提现。
需求文档约定(§20.2):
| 后台操作 | 产品语义 | 应对 handleFirstCashoutResult |
|---|---|---|
| 拒绝退钱 | 失败,可重试 | success=false, rejected=false → 档位 ready |
| 拒绝扣钱 | 风控拒绝 | success=false, rejected=true → 档位 rejected |
slot_console 已有消费端(EventBus.php L133–140),但 全库无生产端 发送 FreeCreditsFirstCashoutFail / Rejected / Success。
flowchart TB
subgraph today [现状]
adminReject[后台拒绝退钱]
payAudit[Pay audit]
walletFail[withdrawFail]
adminReject --> payAudit --> walletFail
end
subgraph target [目标]
adminReject2[后台拒绝退钱]
payAudit2[Pay audit 识别 bizType]
skipWallet[跳过钱包退冻]
mqFail[MQ FreeCreditsFirstCashoutFail]
fcLogic[handleFirstCashoutResult ready]
adminReject2 --> payAudit2 --> skipWallet
payAudit2 --> mqFail --> fcLogic
end
改造范围(主改 slot_pay,常量补 slot_lib)
1. 订单落库时持久化 biz_type
文件:slot_pay/app/entity/WithdrawalOrderEntity.php — creatOrder()
- 若
WithdrawalInfo::$bizType非空,写入data_snapshot.biz_type(表无独立字段,用现有 JSON 即可)。 - 常量与 C 端一致:
free_credit_first_cashout(见FreeCreditsLogic::BIZ_TYPE_FIRST_CASHOUT)。
新增私有方法(同文件):
private function isFreeCreditFirstCashout(?WithdrawalInfo $info = null, ?self $order = null): bool
- 优先读
$info->bizType;审核/回调阶段读$order->data_snapshot['biz_type']。
2. 申请提现:第一档不冻普通钱包
文件:同上 — apply()
isFreeCreditFirstCashout($info)为 true 时:- 跳过
withdrawFrozen、UserTagService::incTodayWithdrawalInfo。 - 仍
creatOrder、人工审核分支、WebSocketMqService::sendWithdrawalUrl保持不变。
- 跳过
catch中仅当曾冻结时才withdrawFail(与现逻辑一致,第一档不会进入)。
对齐 WithdrawalInfo 注释 与需求「第一档不进入普通钱包 withdraw」。
3. 审核拒绝/扣钱:分支 + 发总线(核心)
文件:同上 — audit()
在 audit_status 设为 2 或 3 后:
| 条件 | 钱包 | Console 总线 type |
handleFirstCashoutResult |
|---|---|---|---|
| 普通提现 + 拒绝退钱 | withdrawFail |
无 | — |
| 普通提现 + 拒绝扣钱 | withdrawDone |
无 | — |
| 第一档 + 拒绝退钱 | 不调钱包;不调 decTodayWithdrawalInfo |
FreeCreditsFirstCashoutFail |
ready,可重提 |
| 第一档 + 拒绝扣钱 | 不调钱包 | FreeCreditsFirstCashoutRejected |
rejected |
实现方式(Pay 依赖已有 ConsoleMqService):
use slotLib\common\mq\ConsoleMqService;
// audit 拒绝分支内:
if ($this->isFreeCreditFirstCashout(null, $order)) {
$event = $type === self::AUDIT_STATUS_REVIEW
? MQBusEntity::TYPE_FREE_CREDITS_FIRST_CASHOUT_FAIL
: MQBusEntity::TYPE_FREE_CREDITS_FIRST_CASHOUT_REJECTED;
ConsoleMqService::getInstance()->sendConsoleBusEvent($order->uid, $event, [
'order_id' => $order->order_id,
]);
} else {
// 现有 withdrawFail / withdrawDone + decTodayWithdrawalInfo
}
站内信逻辑可保留(第一档同样通知用户)。
4. 总线常量集中到 slot_lib
文件:slot_lib/src/entity/mq/MQBusEntity.php
新增(与 console 现有字符串一致):
TYPE_FREE_CREDITS_FIRST_CASHOUT_SUCCESS = 'FreeCreditsFirstCashoutSuccess'TYPE_FREE_CREDITS_FIRST_CASHOUT_FAIL = 'FreeCreditsFirstCashoutFail'TYPE_FREE_CREDITS_FIRST_CASHOUT_REJECTED = 'FreeCreditsFirstCashoutRejected'
slot_console/app/entity/mq/MQBusEntity.php 可改为 use slotLib\entity\mq\MQBusEntity as LibMQBusEntity 引用常量(可选,避免双份字符串)。
5. 顺带补齐:打款结果回调(建议同 PR)
EventWithdrawal::updateOrder() 在成功/失败时同样未区分第一档,会误调 withdrawSuccess / withdrawFail。
在同一 PR 中按 data_snapshot.biz_type 分支:
- 成功 → 发
FreeCreditsFirstCashoutSuccess,不withdrawSuccess - 失败 → 发
FreeCreditsFirstCashoutFail,不withdrawFail - 普通单保持现状
否则后台「通过」后渠道失败/成功,档位状态仍会错乱。
不改动的部分
- 管理后台 UI:无需改,仍调
audit(record, 2|3)。 FreeCreditsLogic::handleFirstCashoutResult:逻辑已满足需求,只补 Pay 侧触发。- 数据库 DDL:用
data_snapshot,无需加列。
历史订单
已产生、且 data_snapshot 无 biz_type 的第一档单:
- 拒绝时仍会走旧
withdrawFail(若当时已冻钱包则退钱正确,但档位仍卡 processing)。 - 运维可对已知
order_id在 console 手工调用handleFirstCashoutResult,或一次性 SQL 回填data_snapshot.biz_type(按free_credits_package.withdraw_order_id关联)。
测试
| 层级 | 内容 |
|---|---|
slot_pay 单测 |
creatOrder 写入 biz_type;isFreeCreditFirstCashout;audit(2) 第一档 mock 不发 withdrawFail、发 MQ(mock ConsoleMqService) |
slot_console 已有 |
FreeCreditsLogicCashoutResultTest 覆盖 handleFirstCashoutResult |
| 手工 | 后台对第一档人工单:拒绝退钱 → C 端档位回 ready 可再提;拒绝扣钱 → rejected |
涉及文件小结
slot_pay/app/entity/WithdrawalOrderEntity.php—creatOrder/apply/audit+ helperslot_pay/app/command/EventWithdrawal.php— 打款结果分支(建议同 PR)slot_lib/src/entity/mq/MQBusEntity.php— 事件常量- (可选)
slot_console/app/entity/mq/MQBusEntity.php— 引用 lib 常量