Files
cursor/plans/首充第一档金额下限_43e84a69.plan.md
ray zhou f71a5c59af ok
2026-05-29 11:21:40 +08:00

107 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: 首充第一档金额下限
overview: 首充定格时,第一档金额应至少为活动配置 `ext_config.first_cash_amount`(千分位),不能仅按 `balanceBeforeQf``min` 压到低于配置;同步调整 `handleFreeCreditInit` 的定格基数与 `calcFirstCashAmount` 公式,并更新单测。
todos:
- id: fix-calc-first-cash
content: 修改 FreeCreditsLogic::calcFirstCashAmount 为至少 ext_config.first_cash_amount
status: completed
- id: update-unit-tests
content: 更新 FreeCreditsLogicAmountTest 与 handleFreeCreditInit 相关单测
status: completed
- id: verify-integration
content: 按需跑 FreeCreditsFirstRechargeFreezeTest 验证落库第一档金额
status: completed
isProject: false
---
# 首充定格:第一档金额不低于配置
## 问题
[`handleFreeCreditInit`](slot_console/app/api/logic/FreeCreditsLogic.php) 当前:
```php
$frozenAmount = max($balanceBeforeQf, 0);
```
定格总额仍用入账前余额(正确),但第一档金额在 [`freezeFirstRecharge`](slot_console/app/api/logic/FreeCreditsLogic.php) 里走:
```php
$firstCashAmount = self::calcFirstCashAmount($frozenAmount, $this->configAmount($config, 'first_cash_amount', ...));
// calcFirstCashAmount = min(frozen, configured)
```
**定格额 < 配置免打码额** 时,第一档会变成定格额本身(例如池内 $6、配置 $20 → 第一档 $6与「第一档最少给 `ext_config.first_cash_amount`」不符。
单测 [`FreeCreditsLogicAmountTest`](slot_console/tests/Unit/FreeCreditsLogicAmountTest.php) 里 `'定格小于配置' => [30, 20, 20]` 已按「至少配置值」写期望,与实现 **不一致**`min(30,20)=20` 碰巧相等,但 `frozen=15, config=20` 会得到 15
## 目标行为
| 字段 | 规则 |
|------|------|
| **定格总额** `frozen_amount_qf` | 仍为入账前免费余额 `balance_before_qf`(需求 §5.3**不**强行抬到配置 |
| **第一档金额** `first_cash_amount_qf` / `package_no=1.amount_qf` | `max(min(定格额, 配置), 配置)` → 等价于 **至少为配置值**:定格 ≥ 配置时取配置上限;定格 < 配置时仍记 **配置值**(运营承诺的档位面额) |
```mermaid
flowchart LR
event[free_credit_init] --> init[handleFreeCreditInit]
init --> freeze[freezeFirstRecharge]
freeze --> frozen["frozen = balanceBefore"]
freeze --> first["firstCash = max(min(frozen, cfg), cfg)"]
```
**边界说明**:若定格额实际小于配置,玩家可提现金额仍受池内 `package.amount_qf` 与钱包冻结额约束;本次按你的要求把 **落库第一档金额** 抬到配置下限,与需求文档 §5.6「定格 < $20 → 第一档 = 定格额」存在冲突——以你本次口径为准;若需「可提现 ≤ 定格」再单独加提现校验。
## 实现(仅 slot_console
### 1. 修改 `calcFirstCashAmount`
文件:[`FreeCreditsLogic.php`](slot_console/app/api/logic/FreeCreditsLogic.php)
```php
public static function calcFirstCashAmount(int $frozenAmount, int $configuredFirstCash): int
{
return max(min($frozenAmount, $configuredFirstCash), $configuredFirstCash);
}
```
- 注释改为:第一档面额不低于配置,且不超过定格总额与配置上限。
- 逻辑上等价于 `return $configuredFirstCash`(当 `configuredFirstCash > 0`);保留 `min(frozen, …)` 形式便于日后若配置为 0 时回退。
### 2. `handleFreeCreditInit` 显式读配置(可选但建议)
在同文件 `handleFreeCreditInit` 内,在调用 `freezeFirstRecharge` 前读取一次配置(便于日志/后续扩展;**定格额仍用 `balanceBeforeQf`**
```php
$configuredFirstCash = $this->configAmount($config, 'first_cash_amount', self::DEFAULT_FIRST_CASH);
$frozenAmount = max($balanceBeforeQf, 0);
// 不把 frozenAmount 改成 max(balanceBefore, configuredFirstCash),避免改变定格总额语义
```
若你希望 **尝试多冻** 到配置下限,可另议;当前计划 **只改第一档金额公式**,不改定格总额。
### 3. 单测
| 文件 | 改动 |
|------|------|
| [`FreeCreditsLogicAmountTest.php`](slot_console/tests/Unit/FreeCreditsLogicAmountTest.php) | 修正/补充:`[15, 20, 20]`(定格小于配置 → 第一档仍为 20保留 `[100, 20, 20]` |
| [`FreeCreditsHandleFreeCreditInitTest.php`](slot_console/tests/Unit/FreeCreditsHandleFreeCreditInitTest.php) | 增加用例:`balanceBefore=15000``first_cash_amount_qf=20000`Harness 落库后 `first_cash_amount_qf` / 第一档 `amount_qf` 为 20000若 Harness 走完整 `freezeFirstRecharge` 需开 DB 或扩展 Harness 断言) |
| 集成测 [`FreeCreditsFirstRechargeFreezeTest`](slot_console/tests/Integration/FreeCreditsFirstRechargeFreezeTest.php) | 当 DB 活动配置 `first_cash_amount_qf=20000``balanceBefore < 20000` 时断言 `player.first_cash_amount_qf === 20000` |
运行Docker
```bash
docker exec -w /app/www/slot/slot_console php82 ./vendor/bin/phpunit \
--filter 'FreeCreditsLogicAmountTest|FreeCreditsHandleFreeCreditInitTest'
```
## 不改动的部分
- **wallet** `maybeSendFreeCreditInit`:仍 `balance_before_qf > 0` 即发事件。
- **定格扣款金额**:仍 `freeCreditsFreeze(frozenAmount)``frozenAmount``balanceBefore` 为准(经 `freezeFirstRecharge``min(…, wallet.balance)` 封顶)。
- **解锁第一档**:仍用 `recharge_unlock_amount` 配置,与本次无关。
## 风险
- 定格 &lt; 配置时,`first_cash_amount_qf` &gt; 实际可冻余额C 端可能展示 $20 但池内不足;提现/保留时需依赖现有 `package.amount_qf` 与钱包校验,必要时后续在 `applyFirstCashoutWithdraw` 增加 `amount_qf <= frozen` 断言。