109 lines
7.2 KiB
Markdown
109 lines
7.2 KiB
Markdown
<!-- 215d598c-9837-4e65-a3e9-850d78cd5f00 -->
|
||
## 周返水(Weekly Cashback)实现方案
|
||
|
||
### 已定决策(来自本轮确认)
|
||
- 二、三:按评审意见修订需求文档、计费/配置与每日返水解耦。
|
||
- 四:方案 B —— 周有效投注每日落库,规避 `user:profit:Ymd` 的 7 天 TTL。
|
||
- 五.1:VIP 费率存活动配置 `ext_config.vip_rates`(type=13),不放 VIP 表。
|
||
- 五.2:VIP 取「周末最后一刻」(结算下周一读当前 VIP 即可)。
|
||
- 五.3:结算上周的同时把「上上周」未领取的置过期。
|
||
- 五.4:VIP0 不进页面,不处理。
|
||
- 五.5/6/7:倒计时对齐周界;四周记录入库;返水 `floor` 取整到厘。
|
||
|
||
### 计费模型(与每日返水的关键差异)
|
||
- 每日返水 = 下注累进分段(`tiers`);周返水 = `周有效投注 × rate(vip%)` 单乘,按 `floor` 取整。
|
||
- 统计周:周一 00:00:00 ~ 周日 23:59:59,**服务器时区**(统一口径,修订文档里"美国时间"表述)。
|
||
- 周有效投注 = 当周 7 天 `rebate_bet` 之和(仅充值用户累加,沿用 `slot_pwa` 现有口径,pwa 无需改动)。
|
||
|
||
### 数据流
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
pwa["slot_pwa incBet 仅充值用户累加 rebate_bet"] --> redis["redis user:profit:Ymd TTL7天"]
|
||
accrue["weeklyRebateAccrue 每天00:05 处理昨日"] --> redis
|
||
accrue --> rec["weekly_rebate_record 当周Pending bet_amount累加"]
|
||
settle["weeklyRebateSettle 周一00:15"] --> rec
|
||
settle --> vip["读当前VIP rate=vip_rates level"]
|
||
settle --> expirePrev["上上周 Claimable -> Expired"]
|
||
claim["C端 claim 上周"] --> wallet["WalletService gift 类型68 打码Y3"]
|
||
```
|
||
|
||
### 落库方案 B(幂等)
|
||
- 新表 `weekly_rebate_record` 增加 `last_accrued_date`(date)。
|
||
- `weeklyRebateAccrue`(每天)处理**昨日**(key 仅 1 天,必在 TTL 内):遍历昨日 `user:profit:` 哈希,充值用户且 `rebate_bet>0` → 定位昨日所属周的记录(无则建 Pending)→ 若 `last_accrued_date < 昨日` 则 `bet_amount += rebate_bet` 且更新 `last_accrued_date`(重跑不重复累加)。
|
||
- C 端「This Week」展示 = `record.bet_amount`(昨日及之前)+ 今日 redis 实时 `rebate_bet`,`rebate = floor(weekBet * rate /100)`(镜像每日返水 `syncTodayPending` 思路)。
|
||
|
||
### 结算/过期(周一)
|
||
- `weeklyRebateSettle`:对上周 `week_start` 的 Pending 记录,读当前 VIP → `rate=vip_rates[level]` → `rebate=floor(bet*rate/100)`;`rebate>0` 置 `Claimable`,写 `vip_level`/`rate_snapshot`/`claimable_at=本周一`/`expire_at=下周一`;同一次把「上上周」`Claimable 且 expire_at<=now` 置 `Expired`。
|
||
- `weeklyRebateExpire`:兜底,`status=Claimable AND expire_at<=now -> Expired`(镜像 `expireDueRecords`)。
|
||
- 顺序:accrue 先于 settle。
|
||
|
||
### 复用 vs 新建
|
||
- 复用骨架:领取短事务 CAS + 钱包入账失败回滚 + 结算结构化日志(镜像 [DailyRebateLogic](slot_console/app/api/logic/DailyRebateLogic.php));`RechargedUidSetService`、`UserProfitEntity`、四态 + `statusLabel`、Controller/Validator 形态。
|
||
- 新建(VIP 费率,不复用 tiers 累进):`WeeklyRebateCalcService::calcRebateLi(betLi, ratePercent)`、`WeeklyRebateConfigService`(解析 `vip_rates`、`maxRate`、`rateForVip`、`canonicalExtConfigForStorage`)。
|
||
|
||
### 文件清单
|
||
slot_lib:
|
||
- [Consts.php](slot_lib/src/common/const/Consts.php) 新增 `ACTIVITY_TYPE_WEEKLY_REBATE=13`、`TRANSACTION_TYPE_WEEKLY_REBATE=68`。
|
||
|
||
slot_console:
|
||
- 模型 `app/model/common/WeeklyRebateRecordModel.php`(四态 + `findByUidAndWeek`)。
|
||
- `RechargeGiftConfigModel` 加 `TYPE_WEEKLY_REBATE=13` 与 `getWeeklyRebateActiveInfo/...ByExactSource`(镜像每日返水方法)。
|
||
- 服务 `app/service/WeeklyRebateCalcService.php`、`app/service/WeeklyRebateConfigService.php`。
|
||
- Logic `app/api/logic/WeeklyRebateLogic.php`(info/claim/accrue/settle/expire)。
|
||
- Controller `app/api/controller/WeeklyRebateController.php`、Validator `app/api/validator/WeeklyRebateValidator.php`。
|
||
- 命令 `app/command/WeeklyRebateAccrue.php`、`WeeklyRebateSettle.php`、`WeeklyRebateExpire.php`。
|
||
- 路由:在 api 路由注册 weekly-rebate info/claim(与每日返水同处)。
|
||
- SQL `db/weekly_rebate.sql`(含 `last_accrued_date`、唯一键 `uniq_uid_week`)。
|
||
- 活动配置入口 [ActivityConfigEntity.php](slot_console/app/entity/activity/ActivityConfigEntity.php) 读写处对 `TYPE_WEEKLY_REBATE` 调 `WeeklyRebateConfigService::canonicalExtConfigForStorage`。
|
||
- 部署文档 `doc/weekly_rebate_deploy.md`(镜像 daily_rebate_deploy)。
|
||
|
||
backend/slot_admin(+ vue):
|
||
- 字典 `activity_type` 增「周返水」value=13;菜单「周返水统计」;活动 type=13 编辑页 VIP 费率(16 档)配置 UI;周返水统计页。
|
||
|
||
slot_wallet:
|
||
- 确认 `TRANSACTION_TYPE_WEEKLY_REBATE=68` 打码归类为 活动赠送 Y3(`SOURCE_TYPE_ACTIVITY_REWARD=3`),与每日返水一致;如有类型白名单需补 68。
|
||
|
||
### 需求文档修订(周返水.md)
|
||
- 领取按钮「昨天返水金额」→「上一周返水金额」。
|
||
- 规则文案「refreshes daily」改为「本周累计实时刷新、每周一结算」。
|
||
- 时区统一为服务器时区(删「美国时间」歧义)。
|
||
- `No Btes` → `No Bets`。
|
||
|
||
### ext_config 标准格式(type=13)
|
||
```json
|
||
{
|
||
"vip_rates": [
|
||
{"vip_level": 0, "rate_percent": 0},
|
||
{"vip_level": 1, "rate_percent": 0.5},
|
||
{"vip_level": 15, "rate_percent": 2.0}
|
||
],
|
||
"banner_image": ""
|
||
}
|
||
```
|
||
|
||
### cron
|
||
- `weeklyRebateAccrue` 每天 00:05;`weeklyRebateSettle` 每周一 00:15;`weeklyRebateExpire` 每周一 00:20(兜底)。
|
||
|
||
### 收尾门禁
|
||
- 改 `app/**/*.php` 后按 `slot-backend-completion-report` Skill 跑 `verify-slot-backend.sh` + docker `php -l`,回复附「检测结果」章节。
|
||
</plan>
|
||
<todos>
|
||
[
|
||
{"id": "doc-fix", "content": "修订 周返水.md 笔误(昨天->上周、daily->weekly、时区统一、No Bets)"},
|
||
{"id": "consts", "content": "slot_lib Consts 新增 ACTIVITY_TYPE_WEEKLY_REBATE=13、TRANSACTION_TYPE_WEEKLY_REBATE=68"},
|
||
{"id": "sql-model", "content": "建 weekly_rebate.sql 与 WeeklyRebateRecordModel(含 last_accrued_date、四态、findByUidAndWeek)"},
|
||
{"id": "config-model-methods", "content": "RechargeGiftConfigModel 加 TYPE_WEEKLY_REBATE 与 getWeeklyRebateActiveInfo 系列方法"},
|
||
{"id": "services", "content": "WeeklyRebateCalcService(VIP费率单乘) 与 WeeklyRebateConfigService(解析 vip_rates/maxRate/rateForVip/canonical)"},
|
||
{"id": "logic", "content": "WeeklyRebateLogic:info/claim(短事务CAS+钱包回滚)/accrue/settle(读VIP+过期上上周)/expire"},
|
||
{"id": "controller-route", "content": "WeeklyRebateController + WeeklyRebateValidator + 路由注册"},
|
||
{"id": "commands", "content": "命令 WeeklyRebateAccrue/Settle/Expire + cron 配置"},
|
||
{"id": "activity-entry", "content": "ActivityConfigEntity 读写 type=13 走 canonicalExtConfigForStorage"},
|
||
{"id": "admin", "content": "slot_admin 字典/菜单/type=13 VIP费率配置页/周返水统计页"},
|
||
{"id": "wallet-verify", "content": "slot_wallet 确认流水类型68 打码归 活动赠送Y3"},
|
||
{"id": "deploy-doc", "content": "编写 weekly_rebate_deploy.md 部署文档"},
|
||
{"id": "verify-gate", "content": "跑 verify-slot-backend.sh + php -l,输出检测结果章节"}
|
||
]
|
||
</todos>
|
||
</invoke>
|