This commit is contained in:
ray zhou
2026-05-29 11:21:40 +08:00
parent 5d6d482efe
commit f71a5c59af
447 changed files with 32245 additions and 116 deletions

View File

@@ -0,0 +1,132 @@
---
name: DailyRebateLogic重构
overview: 按 `php-code` 规范重构每日返水领取链路:`claim` 编排化、BusinessException、Model 条件更新;同步调整 Controller 异常映射。`settleDate`/`info` 仅做必要小抽取,不改业务语义。
todos:
- id: model-mark-claimed
content: DailyRebateRecordModel 增加 markClaimedIfClaimable + PHPDoc
status: pending
- id: logic-claim-refactor
content: DailyRebateLogicclaim 拆 assert/perform/formatBusinessException
status: pending
- id: logic-info-helper
content: 可选isClaimableRecord 供 info 与 assert 复用
status: pending
- id: controller-exception
content: DailyRebateControllercatch BusinessException → FAILED
status: pending
- id: verify-smoke
content: 跑 verify-slot-backend.sh确认无 RuntimeException 新增
status: pending
isProject: false
---
# DailyRebateLogic 规范重构
## 范围AskQuestion 中断,按推荐默认)
- **必做**[`claim`](slot_console/app/api/logic/DailyRebateLogic.php)、[`DailyRebateController::claim`](slot_console/app/api/controller/DailyRebateController.php)、[`DailyRebateRecordModel`](slot_console/app/model/common/DailyRebateRecordModel.php)
- **轻量**`info()` 抽取「是否可领」判断为 private`assertClaimableRecord` 复用逻辑
- **不改语义**`settleDate` / `expireDueRecords` / Redis 结算逻辑保持行为一致,仅在有重复代码时抽 1 个 private可选
## 现状问题(对照 php-code
[`claim`](slot_console/app/api/logic/DailyRebateLogic.php) L92157
- 6 段 `RuntimeException` if 墙
- CAS 写在 Logic 内联,未沉淀 Model
- Controller `catch RuntimeException` + `PARAMS_ERROR`verify 会拦新增行)
参照:[`FreeCreditsLogic::claim`](slot_console/app/api/logic/FreeCreditsLogic.php)`assert*` + `BusinessException` + 状态更新)
## 目标结构
```mermaid
sequenceDiagram
participant C as DailyRebateController
participant L as DailyRebateLogic
participant M as DailyRebateRecordModel
participant W as WalletService
C->>L: claim(uid, source, statDate)
L->>L: assertActivityEnabled
L->>L: assertUserDeposited
L->>M: findByUidAndDate
L->>L: assertClaimableRecord
L->>M: markClaimedIfClaimable
L->>W: gift(rebate, DAILY_REBATE, remark)
L-->>C: formatClaimResult
```
### 1. Model条件更新
在 [`DailyRebateRecordModel`](slot_console/app/model/common/DailyRebateRecordModel.php) 新增:
```php
/**
* 待领取状态下标记为已领取CAS
*
* @return int 影响行数1 表示成功
*/
public static function markClaimedIfClaimable(int $id): int
```
实现:`where id` + `where status = STATUS_CLAIMABLE``STATUS_CLAIMED` + `claimed_at`
### 2. Logic`claim` 拆分为编排 + assert + perform
| 方法 | 职责 |
|------|------|
| `claim()` public | 编排 ≤20 行:`resolveSource` → 默认 `statDate` → assert → `performClaim` → 返回 |
| `assertActivityEnabled(string $source)` | 活动未开 → `BusinessException` |
| `assertUserDeposited(int $uid)` | 未充值 → `BusinessException` |
| `assertClaimableRecord(?DailyRebateRecordModel $record)` | 不存在/状态/金额/过期 → 各一条 `BusinessException`(合并原 4 条 if |
| `performClaim(int $uid, DailyRebateRecordModel $record, string $statDate)` | 事务:`markClaimedIfClaimable``WalletService::gift` → commit`affected !== 1` 或 wallet 空 → `BusinessException` |
| `formatClaimResult(...)` | 返回 `stat_date` / `rebate_amount` / `display` / `balance` |
- 使用 `support\exception\BusinessException`(与 FreeCredits 一致)
- `@throws` 改为 `BusinessException``\Throwable`(钱包失败)
- **钱包 biz_id**`WalletService::gift()` 内部已 `generateOrderId`[`slot_lib/src/services/WalletService.php`](slot_lib/src/services/WalletService.php) L262265幂等依赖 **记录 CAS**remark 保持 `每日返水 {statDate}` 便于对账
### 3. Logic`info` 轻量复用(可选)
抽取 `isClaimableRecord(DailyRebateRecordModel $record): bool`status + amount + expire`info()``claimable` 块与 `assertClaimableRecord` 共用,避免两套判断漂移。
### 4. Controller异常映射
[`DailyRebateController::claim`](slot_console/app/api/controller/DailyRebateController.php)
```php
} catch (BusinessException $e) {
return $this->errorCode(ErrorCode::FAILED, $e->getMessage());
}
```
- 对齐 [`SignController`](slot_console/app/api/controller/SignController.php)(业务失败 `FAILED` + 文案)
- **API 变更**`code``40003`PARAMS_ERROR变为 `1`FAILED文案仍为中文业务提示。若 PWA 强依赖 `40003`,可在计划中改为保留 `PARAMS_ERROR`(实现时二选一,默认 `FAILED`
不采用 FreeCredits「无 catch、走全局 Handler」方式避免未捕获时变成 `SYSTEM_ERROR`50001
### 5. 不动 / 谨慎
- **事务边界**:维持「先 CAS 再 gift 再 commit」不在此 PR 改为「先 wallet 后 DB」或 Outbox
- **`settleDate`**:逻辑不变;可选抽 `settleOneUserFromRedis(...)` 降低 foreach 嵌套(非必须)
## 文件清单
| 文件 | 变更 |
|------|------|
| `slot_console/app/model/common/DailyRebateRecordModel.php` | +`markClaimedIfClaimable` |
| `slot_console/app/api/logic/DailyRebateLogic.php` | 重构 `claim`;可选 `isClaimableRecord` |
| `slot_console/app/api/controller/DailyRebateController.php` | `BusinessException` + `FAILED` |
## 验收
1. `docker exec -w /app/www/slot/slot_console php82 php webman dailyRebateSettle --date=...`(如有环境)结算后,已充值用户可领昨日返水
2. 重复领取 → 业务错误文案DB 仍为 `CLAIMED`,不重复入账
3. `~/.cursor/hooks/verify-slot-backend.sh` → PASS无新增 `RuntimeException` 业务态)
4. 最终回复含 `PHPDoc: checked`(触及符号补全 `@throws BusinessException`
## 风险与回滚
- **PWA 错误码**:若前端按 `code===40003` 分支,需同步前端或 Controller 保留 `PARAMS_ERROR`
- 回滚:还原 3 个文件即可