6.0 KiB
6.0 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | |||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DailyRebateLogic重构 | 按 `php-code` 规范重构每日返水领取链路:`claim` 编排化、BusinessException、Model 条件更新;同步调整 Controller 异常映射。`settleDate`/`info` 仅做必要小抽取,不改业务语义。 |
|
false |
DailyRebateLogic 规范重构
范围(AskQuestion 中断,按推荐默认)
- 必做:
claim、DailyRebateController::claim、DailyRebateRecordModel - 轻量:
info()抽取「是否可领」判断为 private,与assertClaimableRecord复用逻辑 - 不改语义:
settleDate/expireDueRecords/ Redis 结算逻辑保持行为一致,仅在有重复代码时抽 1 个 private(可选)
现状问题(对照 php-code)
claim L92–157:
- 6 段
RuntimeExceptionif 墙 - CAS 写在 Logic 内联,未沉淀 Model
- Controller
catch RuntimeException+PARAMS_ERROR(verify 会拦新增行)
参照:FreeCreditsLogic::claim(assert* + BusinessException + 状态更新)
目标结构
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 新增:
/**
* 待领取状态下标记为已领取(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.phpL262–265);幂等依赖 记录 CAS,remark 保持每日返水 {statDate}便于对账
3. Logic:info 轻量复用(可选)
抽取 isClaimableRecord(DailyRebateRecordModel $record): bool(status + amount + expire),供 info() 的 claimable 块与 assertClaimableRecord 共用,避免两套判断漂移。
4. Controller:异常映射
} catch (BusinessException $e) {
return $this->errorCode(ErrorCode::FAILED, $e->getMessage());
}
- 对齐
SignController(业务失败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 |
验收
docker exec -w /app/www/slot/slot_console php82 php webman dailyRebateSettle --date=...(如有环境)结算后,已充值用户可领昨日返水- 重复领取 → 业务错误文案,DB 仍为
CLAIMED,不重复入账 ~/.cursor/hooks/verify-slot-backend.sh→ PASS(无新增RuntimeException业务态)- 最终回复含
PHPDoc: checked(触及符号补全@throws BusinessException)
风险与回滚
- PWA 错误码:若前端按
code===40003分支,需同步前端或 Controller 保留PARAMS_ERROR - 回滚:还原 3 个文件即可