Files
2026-10-12 02:10:43 +00:00

481 lines
24 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.
# Mock Gateway
本项目是 **独立 Git 仓库** 的本地 Mock 网关,用于模拟 eWallet 后端依赖的 Bally/EDIP 接口,避免在 `Backend` 主代码中持续保留绕过逻辑。
## 已内置的 Mock 接口
- `POST /edip/v1/token/get`
- `POST /edip/v1/token/refresh`
- `POST /ewl/bal/v1/cardpin/validate`
- `POST /ewl/promotion/v1/promotion/all`
- `POST /ewl/bal/v1/promotion/all` (兼容旧地址)
- `POST /ewl/promotion/v1/promotion/backdate/all`
- `POST /ewl/bal/v1/promotion/backdate/all` (兼容旧地址)
- `POST /ewl/mkt-rm/v1/team/hierarchy`
- `POST /ewl/bal/v1/prize/redeem`
- `POST /ewl/bal/v1/point/void`
- `POST /ewl/promotion/v1/redeemedpromotion/detail`
- `POST /ewl/bal/v1/redeemedpromotion/detail` (兼容旧地址)
- `POST /ewl/promotion/v1/playerpromotion/redeem`
- `POST /ewl/bal/v1/playerpromotion/redeem` (兼容旧地址)
- `POST /ewl/promotion/v1/redeemedpromotion/void`
- `POST /ewl/bal/v1/redeemedpromotion/void` (兼容旧地址)
- `POST /ewl/edip/v1/member/profile`
- `POST /ewl/bal/v1/player/image`
- `POST /ewl/bal/v1/player/earn`
- `POST /api/v1/prize-redemptions/sync`
- `GET /healthz`
## 已内置的 LDAP Mock(新增)
- 协议:LDAPv3
- 默认监听:`ldap://0.0.0.0:1389`
- 支持能力:`Simple Bind` + `Search`
固定行为(与对接约定一致):
1. manager bind DN:`cn=s-cicd-app,OU=ServiceAccount,dc=macausjm-glp,dc=com`
2. 用户搜索:base `dc=macausjm-glp,dc=com` + filter `(sAMAccountName={username})`
3. 组搜索:base `OU=SecurityGroups,OU=GLPUsers,dc=macausjm-glp,dc=com` + filter `(member={userDn})`
4. 用户条目属性:`sAMAccountName` / `cn` / `mail` / `memberOf`
5. 组条目属性:`cn` / `member`
并且支持用户 DN + 密码直接 bind 成功(基于内置默认用户或 `MOCK_LDAP_USERS_JSON` 配置用户)。
另外默认开启“任意用户名/密码放行”联调模式(`MOCK_LDAP_ALLOW_ANY_USER_MODE=true`):
- 前端输入任意账号密码都可通过后端 LDAP 认证
- `(sAMAccountName={username})` 会按 `{username}` 动态返回用户条目
- `(member={userDn})` 会返回组条目(默认 `SG-APP-EWALLET-SUPER-ADMIN`)
推荐做法:通过 `MOCK_LDAP_USERS_JSON` / `MOCK_LDAP_GROUPS_JSON` 在 `Mock_Gateway` 侧配置用户与用户组,不要再在 `Backend` 代码里硬编码开发账号或组别。
## 本地启动
```bash
cd Mock_Gateway
npm install
cp .env.example .env
npm run start
```
开发联调建议使用自动重启模式(监听 `src/` 与 `.env` 变更):
```bash
npm run dev
```
默认监听:`http://127.0.0.1:19090`
LDAP 默认监听:`ldap://0.0.0.0:1389`
## Promotion 完整链路 mock
默认的 `playerpromotion/redeem` 仍然只是静态回包。
如果你要在本地继续联调 promotion 首打、redeemed history、reprint 这一整条链路,可以开启下面这组桥接配置,让 `Mock_Gateway` 在 promotion redeem 成功后继续:
1. 登录本地 `Backend`
2. 调用真实 `POST /api/v1/prize-redemptions`
3. 把同一笔 `redemptionId` 记录进 mock 的 `redeemedpromotion/detail`
建议同时满足以下前提:
- 本地 `Backend` 已启动
- 本地 `Backend` 已接到当前 `Mock_Gateway` 的 LDAP mock
- 测试会员在本地 wallet 里对 `MOCK_PROMOTION_REDEMPTION_SOURCE_BUCKET` 有足够余额
推荐配置:
```bash
MOCK_PROMOTION_REDEMPTION_BRIDGE_ENABLED=true
MOCK_PROMOTION_REDEMPTION_BRIDGE_BASE_URL=http://127.0.0.1:8080
MOCK_PROMOTION_REDEMPTION_BRIDGE_LOGIN_PASSWORD=mock-password
MOCK_PROMOTION_REDEMPTION_BRIDGE_TIMEOUT_MS=30000
MOCK_PROMOTION_REDEMPTION_INITIATE_SOURCE=PROMOTION_MODULE
MOCK_PROMOTION_REDEMPTION_SOURCE_BUCKET=m-comp
```
说明:
- `MOCK_PROMOTION_REDEMPTION_BRIDGE_LOGIN_USERNAME` 留空时,默认复用本次 redeem 请求里的 `loginId`
- `MOCK_PROMOTION_REDEMPTION_SOURCE_BUCKET` 默认用 `m-comp` 作为 source wallet bucket
- 桥接成功后,`/ewl/bal/v1/redeemedpromotion/detail` 会优先返回本次实际生成的 mock redeemed record
### Promotion issue-to-wallet 控制
当前 `Mock_Gateway` 已支持两层控制 promotion redeem -> 本地 `prize-redemptions` 的 `issueTargetToWallet`:
1. 显式覆盖,优先级最高
2. 现有推断,作为兜底
显式覆盖支持两种写法:
- 请求级:
- `data.issueTargetToWallet: [true, false, ...]`,按 `outcomeId` 顺序逐项覆盖;同一个 `outcomeId` 重复出现且每次选择不同 `Open Item / Auto Settle` 时,必须走这个数组
- `data.issueTargetToWalletByOutcomeId: { "11330011": true, "11330012": false }`,按 outcomeId 精确覆盖
- fixture 级:
- `outcomeList[].mockIssueTargetToWallet`
- `outcomeList[].prize.mockIssueTargetToWallet`
当以上显式覆盖都没有提供时,才回退到现有推断规则:
- `gisPrizeIdentifier[index]` 非空 -> `issueTargetToWallet=false`
- 否则 `deliveryMode=EXTERNAL_ONLY` -> `false`
- 其他情况 -> `true`
这意味着:
- 对 `USER_CHOICE` prize,如需稳定复现同一个 outcome 在 openitem / autosettle 之间切换,推荐直接在 mock 请求或 fixture 中提供显式覆盖,不要只依赖 `deliveryMode`
- 如果一个请求里允许同一个 `outcomeId` 重复出现且每次选择不同,优先使用 `issueTargetToWallet` 数组;`issueTargetToWalletByOutcomeId` 只适合一个 outcomeId 对应一个固定值的场景
- 如果调用方需要,也可以通过 body 的 `issueTargetToWalletByOutcomeId` / `issueTargetToWallet`,或自定义 header `X-Ewallet-Mock-Issue-Target-To-Wallet-By-Outcome-Id` 给 mock 传入显式覆盖;未提供时仍按当前默认推断执行
- 旧链路不受影响;未提供覆盖时仍保持当前默认行为
### UI 点测同一个 outcome 的本地预设
如果不改 Backend,但希望在 UI 上对同一个 outcome 反复点测 `Open Item / Auto Settle`,可以先写入 mock runtime override:
```bash
curl -s -X POST http://127.0.0.1:19090/mock-api/promotion-redeem/fulfillment-overrides \
-H 'Content-Type: application/json' \
-d '{
"accountNum": "80010991",
"promotionId": 11330,
"promotionRuleId": 1133001,
"outcomeId": 11330011,
"issueTargetToWallet": false
}'
```
说明:
- `issueTargetToWallet=true` 表示本次同一个 outcome 走 `Open Item`
- `issueTargetToWallet=false` 表示本次同一个 outcome 走 `Auto Settle`
- 写入后,直接在 UI 点同一个 outcome 即可;mock 会优先使用这份 runtime override
- override 默认会持久化到 `./runtime/promotion-redeem-fulfillment-overrides.json`,重启 `Mock_Gateway` 后仍会保留
- 可通过 `GET /mock-api/promotion-redeem/fulfillment-overrides` 查看当前预设
- 可通过 `DELETE /mock-api/promotion-redeem/fulfillment-overrides?accountNum=80010991&promotionId=11330&promotionRuleId=1133001&outcomeId=11330011` 清除单条预设
## 与 Backend 集成
在 Backend 启动环境中设置:
```bash
MOCK_GATEWAY_BASE_URL=http://127.0.0.1:19090
BALLY_BASE_URL=${MOCK_GATEWAY_BASE_URL}
EDIP_BASE_URL=${MOCK_GATEWAY_BASE_URL}
BALLY_REDEEM_BASE_URL=${MOCK_GATEWAY_BASE_URL}
BALLY_PROMOTION_BASE_URL=${MOCK_GATEWAY_BASE_URL}
# 建议关闭旧的本地 member 直返 mock,改走网关
BALLY_MEMBER_QUERY_LOCAL_MOCK_ENABLED=false
```
## Task12085 本地故障注入
当前 `Mock_Gateway` 已支持直接注入 Member Profile 两类关键故障:
1. `503` / 服务不可用
```bash
MOCK_MEMBER_PROFILE_FORCE_STATUS_CODE=503
MOCK_MEMBER_PROFILE_FORCE_ERROR_CODE=MOCK_503
MOCK_MEMBER_PROFILE_FORCE_ERROR_MSG='Mock member profile unavailable'
```
2. 响应超时
```bash
MOCK_MEMBER_PROFILE_DELAY_MS=15000
```
建议:
- `MOCK_MEMBER_PROFILE_DELAY_MS` 需要大于 Backend 当前 member profile 调用的阻塞超时,才能稳定触发超时
- 如果你只想打 member profile 故障,保持 `MOCK_EDIP_FORCE_ERROR_CODE` 为空,让 token 继续正常返回
- 测完后把这些变量清空并重启 `Mock_Gateway`
## 快速验证
```bash
curl -s http://127.0.0.1:19090/healthz
curl -s -X POST http://127.0.0.1:19090/edip/v1/token/get \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"account":"a","password":"b","key":"k","secret":"s"}}'
curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/cardpin/validate \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"accountNum":"810006843","pin":"1234"}}'
curl -s -X POST http://127.0.0.1:19090/ewl/promotion/v1/promotion/all \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"accountNum":"800048718"}}'
curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/promotion/all \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"accountNum":"800048718"}}'
curl -s -X POST http://127.0.0.1:19090/ewl/mkt-rm/v1/team/hierarchy \
-H 'Content-Type: application/json' \
-d '{"schema":{"terminalCode":"MOCK-PC"},"data":{"userName":"mock.user","staffId":"M000001"}}'
curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/prize/redeem \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"accountNum":"800048718","prizeCode":"MOCK"}}'
curl -s -X POST http://127.0.0.1:19090/api/v1/prize-redemptions/sync \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"correlationId":"mock-correlation-id"}}'
curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/point/void \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"transId":"mock-redeem-id"}}'
curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/redeemedpromotion/detail \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"accountNum":"800048718"}}'
curl -s -X POST http://127.0.0.1:19090/ewl/promotion/v1/playerpromotion/redeem \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"accountNum":"800048718","promotionId":100002}}'
curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/playerpromotion/redeem \
-H 'Content-Type: application/json' \
-d '{
"schema": {},
"data": {
"accountNum": "80010991",
"promotionId": 11330,
"promotionRuleId": 1133001,
"outcomeId": [11330011, 11330012, 11330013],
"issueTargetToWalletByOutcomeId": {
"11330011": true,
"11330012": false,
"11330013": false
}
}
}'
curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/playerpromotion/redeem \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"accountNum":"800048718","promotionId":100002}}'
curl -s -X POST http://127.0.0.1:19090/ewl/promotion/v1/redeemedpromotion/void \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"redeemedId":<上一步 detail 响应里的 redemptionId>}}'
curl -s -X POST http://127.0.0.1:19090/ewl/bal/v1/redeemedpromotion/void \
-H 'Content-Type: application/json' \
-d '{"schema":{},"data":{"redeemedId":<上一步 detail 响应里的 redemptionId>}}'
# LDAP manager bind(默认 manager 密码可留空,便于 Backend 只改 LDAP_URL)
ldapsearch -x -H ldap://127.0.0.1:1389 \
-D "cn=s-cicd-app,OU=ServiceAccount,dc=macausjm-glp,dc=com" \
-w "any-password" \
-b "dc=macausjm-glp,dc=com" \
"(sAMAccountName=mock.user)" sAMAccountName cn mail memberOf
# LDAP user bind(DN + 密码)
ldapsearch -x -H ldap://127.0.0.1:1389 \
-D "cn=mock.user,OU=GLPUsers,dc=macausjm-glp,dc=com" \
-w "mock-user-password" \
-b "OU=SecurityGroups,OU=GLPUsers,dc=macausjm-glp,dc=com" \
"(member=cn=mock.user,OU=GLPUsers,dc=macausjm-glp,dc=com)" cn member
# 建议把默认组名设置成 Backend 角色表已有 code(如 `SG-APP-EWALLET-SUPER-ADMIN`),更容易看到非空 permissions
```
## 页面数据模板(JSON)
- `fixtures/token.get.json`:`/edip/v1/token/get` 成功响应模板
- `fixtures/member.profile.json`:`/ewl/edip/v1/member/profile` 成功响应模板
- `fixtures/promotions.capture.800048718.json`:`/ewl/promotion/v1/promotion/all` 抓包模板
- `fixtures/promotions.capture.<account>.json`:按会员号隔离的 promotion fixture;存在同名文件时,mock 会优先对该会员返回该文件内容
- promotion fixture 可额外带 `outcomeList[].mockIssueTargetToWallet` 或 `outcomeList[].prize.mockIssueTargetToWallet`,用于稳定指定某个 outcome 走 openitem / autosettle
当前已补一条专用于完整链路测试的会员:
- `80010991`
- promotionId:`10991`
- promotion:`LP-MOCK-REPRINT-CHAIN`
- ruleId:`1099101`
- outcomeId:`10991011`
- targetPrizeCode:`lp-ee-nsuwr-5pts-20-fb`
- 另有 3-outcome 的 `USER_CHOICE` 测试 promotion:
- promotionId:`11330`
- promotion:`LP-MOCK-USER-CHOICE-3-OUTCOMES`
- ruleId:`1133001`
- outcomeId:`11330011` -> `it-test-fb-$1`
- outcomeId:`11330012` -> `it-test-nnpc-$1`
- outcomeId:`11330013` -> `it-test-ebo-$1`
- 这 3 个 outcome 都可在 UI 上分别切 `Open Item / Auto Settle`,用于本地验证 promotion redeem -> prize-redemptions -> redeemed detail 整条链路
说明:
- 以上模板用于维护响应“静态骨架”
- 动态字段仍由网关运行时覆盖(如 `accessToken`、`refreshToken`、`accountNum`、`playerId`、以及 LDAP 用户相关字段)
## 代码结构(已拆分)
- `src/server.js`:仅保留启动、路由装配、404 与 LDAP 启动
- `src/ldap/createMockLdapService.js`:LDAP 相关逻辑独立维护
- `src/context/createMockContext.js`:共享配置、fixture 加载、通用工具函数
- `src/routes/**`:每个接口路径一个独立文件(便于新增与变更)
## 常用环境变量
- `MOCK_PROMOTION_CAPTURE_FILE`:promotion 抓包文件路径(默认读取仓库内 `./fixtures/promotions.capture.800048718.json`)
- `MOCK_PROMOTION_MAX_ITEMS`:promotion 返回上限(eligible/entitled 各自限制,默认 `30`)
- `MOCK_TASK_10766_ENABLED`:开启 Task 10766 复现场景(默认 `false`)
- `MOCK_TASK_10766_ACCOUNT_NUM`:Task 10766 固定 mock 会员号(默认 `80010766`)
- `MOCK_TASK_10766_PROMOTION_CAPTURE_FILE`:Task 10766 promotion fixture(默认 `./fixtures/promotions.capture.10766.json`)
- `MOCK_TASK_10766_MEMBER_EBONUS`:Task 10766 会员资料接口返回的 eBonus 数值(默认 `8888`)
- `MOCK_TASK_10766_REDEEM_ERROR_CODE` / `MOCK_TASK_10766_REDEEM_ERROR_MSG` / `MOCK_TASK_10766_REDEEM_RESULT`:Task 10766 的 `playerpromotion/redeem` 定向失败控制
- `MOCK_TASK_10852_ENABLED`:开启 Task 10852 多 outcome promotion 复现场景(默认 `false`)
- `MOCK_TASK_10852_ACCOUNT_NUM`:Task 10852 固定 mock 会员号(默认 `80010852`)
- `MOCK_TASK_10852_PROMOTION_CAPTURE_FILE`:Task 10852 promotion fixture,默认使用隔离的 entitled 双 outcome 抓包 `./fixtures/promotions.capture.10852.json`
- `MOCK_TASK_10852_MEMBER_EBONUS`:Task 10852 会员资料接口返回的 eBonus 数值(默认 `188`)
- `MOCK_TOKEN_GET_FIXTURE_FILE`:`/edip/v1/token/get` JSON 模板文件路径(默认 `./fixtures/token.get.json`)
- `MOCK_MEMBER_PROFILE_FIXTURE_FILE`:`/ewl/edip/v1/member/profile` JSON 模板文件路径(默认 `./fixtures/member.profile.json`)
- `MOCK_MEMBER_PROFILE_FORCE_STATUS_CODE`:`/ewl/edip/v1/member/profile` 强制返回指定 HTTP 状态码,例如 `503`
- `MOCK_MEMBER_PROFILE_FORCE_ERROR_CODE`:配合 `MOCK_MEMBER_PROFILE_FORCE_STATUS_CODE` 返回错误码
- `MOCK_MEMBER_PROFILE_FORCE_ERROR_MSG`:配合 `MOCK_MEMBER_PROFILE_FORCE_STATUS_CODE` 返回错误信息
- `MOCK_MEMBER_PROFILE_DELAY_MS`:`/ewl/edip/v1/member/profile` 延迟响应毫秒数,可用于本地模拟超时
- `MOCK_TEAM_HIERARCHY_STATUS`:`team/hierarchy` 的 `status`(默认 `true`)
- `MOCK_TEAM_HIERARCHY_ERROR_CODE` / `MOCK_TEAM_HIERARCHY_MESSAGE`:`team/hierarchy` 错误模拟
- `MOCK_TEAM_HIERARCHY_ROLE` / `MOCK_TEAM_HIERARCHY_DEPARTMENT` / `MOCK_TEAM_HIERARCHY_TAGS`:`team/hierarchy` 返回字段
- `MOCK_PRIZE_REDEEM_ERROR_CODE` / `MOCK_PRIZE_REDEEM_ERROR_MSG` / `MOCK_PRIZE_REDEEM_VALUE`:`prize/redeem` 返回控制(`MOCK_PRIZE_REDEEM_VALUE` 留空时自动生成交易号)
- `MOCK_POINT_VOID_ERROR_CODE` / `MOCK_POINT_VOID_ERROR_MSG` / `MOCK_POINT_VOID_RESULT`:`point/void` 返回控制
- `MOCK_REDEEMED_PROMOTION_DETAIL_ERROR_CODE` / `MOCK_REDEEMED_PROMOTION_DETAIL_ERROR_MSG`:`redeemedpromotion/detail` 返回控制
- `MOCK_REDEEMED_PROMOTION_DETAIL_INCLUDE_DEFAULT_RECORD`:是否返回默认一条 `outcomeList`(默认 `true`)
- `MOCK_REDEEMED_PROMOTION_DETAIL_VOIDED`:默认记录是否标记已作废(默认 `false`)
- `MOCK_PLAYERPROMOTION_REDEEM_ERROR_CODE` / `MOCK_PLAYERPROMOTION_REDEEM_ERROR_MSG` / `MOCK_PLAYERPROMOTION_REDEEM_RESULT`:`playerpromotion/redeem` 返回控制
- `MOCK_PROMOTION_REDEMPTION_BRIDGE_ENABLED`:开启 promotion redeem -> 本地 `prize-redemptions` 桥接(默认 `false`)
- `MOCK_PROMOTION_REDEMPTION_BRIDGE_BASE_URL`:本地 Backend 基地址(默认 `http://127.0.0.1:8080`)
- `MOCK_PROMOTION_REDEMPTION_BRIDGE_LOGIN_USERNAME` / `MOCK_PROMOTION_REDEMPTION_BRIDGE_LOGIN_PASSWORD`:桥接调用 Backend 登录用账号;用户名留空时默认复用本次 redeem 的 `loginId`
- `MOCK_PROMOTION_REDEMPTION_BRIDGE_TIMEOUT_MS`:桥接调用超时毫秒数(默认 `30000`);本地完整链路联调建议至少保留 `30000`
- `MOCK_PROMOTION_REDEMPTION_INITIATE_SOURCE`:桥接到 `prize-redemptions` 时写入的 `initiateSource`(默认 `PROMOTION_MODULE`)
- `MOCK_PROMOTION_REDEMPTION_SOURCE_BUCKET`:桥接到 `prize-redemptions` 时使用的 source wallet bucket(默认 `m-comp`)
- `MOCK_PROMOTION_REDEMPTION_ID_START`:mock redeemed history 的起始 `redemptionId`;留空时默认用进程启动时的 Unix 秒级时间戳作为 seed,且会限制在 Backend `int` 可解析范围内,避免 Mock_Gateway 重启后重复复用旧 `redemptionId`
- `MOCK_REDEEMEDPROMOTION_VOID_ERROR_CODE` / `MOCK_REDEEMEDPROMOTION_VOID_ERROR_MSG` / `MOCK_REDEEMEDPROMOTION_VOID_RESULT`:`redeemedpromotion/void` 返回控制
- `MOCK_PRIZE_REDEMPTIONS_SYNC_SUCCESS` / `MOCK_PRIZE_REDEMPTIONS_SYNC_MESSAGE`:`/api/v1/prize-redemptions/sync` 返回控制
- `MOCK_LDAP_ENABLED`:是否启用 LDAP mock(默认 `true`)
- `MOCK_LDAP_HOST`:LDAP 监听地址(默认 `0.0.0.0`)
- `MOCK_LDAP_PORT`:LDAP 监听端口(默认 `1389`)
- `MOCK_LDAP_BASE_DN`:LDAP 基础 DN(默认 `dc=macausjm-glp,dc=com`)
- `MOCK_LDAP_MANAGER_DN`:manager bind DN(默认 `cn=s-cicd-app,OU=ServiceAccount,dc=macausjm-glp,dc=com`)
- `MOCK_LDAP_GROUP_BASE_DN`:组搜索 base(默认 `OU=SecurityGroups,OU=GLPUsers,dc=macausjm-glp,dc=com`)
- `MOCK_LDAP_ALLOW_ANY_USER_MODE`:任意用户名/密码放行模式(默认 `true`)
- `MOCK_LDAP_ALLOW_ANY_USER_OU`:动态用户 DN 的 OU 段(默认 `OU=GLPUsers`)
- `MOCK_LDAP_ALLOW_ANY_USER_GROUP_CN`:动态用户默认组名(默认 `SG-APP-EWALLET-SUPER-ADMIN`)
- `MOCK_LDAP_ALLOW_ANY_USER_MAIL_DOMAIN`:动态用户邮箱域名(默认 `macausjm-glp.com`)
- `MOCK_LDAP_MANAGER_PASSWORD`:manager bind 密码;留空时允许任意密码(便于仅改 `LDAP_URL` 联调)
- `MOCK_LDAP_DEFAULT_USER_*`:默认单用户 mock 配置
- `MOCK_LDAP_USERS_JSON`:JSON 数组,多用户覆盖配置
## Task 10766 复现场景
打开 `.env`,加入或覆盖以下配置:
```bash
MOCK_TASK_10766_ENABLED=true
MOCK_TASK_10766_ACCOUNT_NUM=80010766
MOCK_TASK_10766_PROMOTION_CAPTURE_FILE=./fixtures/promotions.capture.10766.json
MOCK_TASK_10766_MEMBER_EBONUS=8888
MOCK_TASK_10766_REDEEM_ERROR_CODE=EWALLET_HTTP_ERROR
MOCK_TASK_10766_REDEEM_ERROR_MSG=ewallet connection failed: 404 NOT_FOUND, {"success":false,"message":"Prize definition not found"}
MOCK_TASK_10766_REDEEM_RESULT=false
```
复现方式:
1. 启动 `Mock_Gateway`
2. 前后端联调继续指向本地 mock 网关
3. 在 `Wallet` 页面搜索会员 `80010766`
4. 切到 `Promotion`
5. 搜索 `cny`
6. 选择 `CNY Gift Set Earn & Get-2026 / GS-8pts-LCH Gift Set Abalone + Scallop`
7. 点击 `Redeem` 并完成确认
预期:
- 会员资料接口返回 `eBonus=8888`
- promotion 列表固定返回 Task 10766 专用 fixture
- `POST /ewl/promotion/v1/playerpromotion/redeem` 固定返回 `Prize definition not found` 场景
- 可稳定复现 10766 对应的 promotion redeem 失败明细展示问题
## Task 10852 复现场景
打开 `.env`,加入或覆盖以下配置:
```bash
MOCK_TASK_10852_ENABLED=true
MOCK_TASK_10852_ACCOUNT_NUM=80010852
MOCK_TASK_10852_PROMOTION_CAPTURE_FILE=./fixtures/promotions.capture.10852.json
MOCK_TASK_10852_MEMBER_EBONUS=188
```
复现方式:
1. 启动 `Mock_Gateway`
2. 前后端联调继续指向本地 mock 网关
3. 在 `Wallet` 页面搜索会员 `80010852`
4. 切到 `Promotion`
5. 搜索 `cny`
6. 选择 `CNY Gift Set Earn & Get-2026`
7. 勾选两个 outcome 后继续兑换流程
预期:
- 会员资料接口返回 `eBonus=188`
- `POST /ewl/promotion/v1/promotion/all` 固定返回可点击的 entitled 双 outcome promotion
- 前端会稳定走到 `targetPrizes` 多项场景,便于验证 10852 的最小修复
## 按会员号自动注入 Promotion Fixture
除了现有的 Task 10766 / 10852 专用开关外,`Mock_Gateway` 现在还支持按会员号自动加载 fixture:
- 文件命名:`fixtures/promotions.capture.<customerId>.json`
- 命中规则:当 `/ewl/promotion/v1/promotion/all` 的 `accountNum` 与文件名中的会员号一致时,自动返回该 fixture
- backdate 文件命名:`fixtures/promotions.backdate.<customerId>.json`
- backdate 命中规则:当 `/ewl/promotion/v1/promotion/backdate/all` 的 `accountNum` 与文件名中的会员号一致时,自动返回该 fixture
- 优先级:Task 10766 / 10852 专用场景优先,其次才是按会员号自动加载的 fixture
示例:
- `fixtures/promotions.capture.800038008.json`
- `fixtures/promotions.capture.80010852.json`
- `fixtures/promotions.backdate.800038008.json`
适用场景:
- 需要保留某个会员的真实采样 promotion 规则
- 想快速补充新的 `minOutcome / maxOutcome / outcomeList / prize` 组合
- 不希望影响默认共享 mock 数据
## 使用本地测试开发网关的时候可以使用以下会员号
按 `Mock_Gateway` 当前代码中的“定向逻辑 / 定向 fixture / 固定路由”统计,特别会员号共有 `5` 个(不含默认模板/示例号):
1. `800038008` - backdate 固定会员号。
`/ewl/promotion/v1/promotion/entitledBackDate` 和 `/ewl/promotion/v1/promotion/entitledBackDate/all` 会固定返回这个会员号的 backdate promotion;仓库里也有它的普通 promotion fixture 和 backdate fixture。
2. `80010766` - Task 10766 专用复现号。
开启 `MOCK_TASK_10766_ENABLED=true` 后,会员资料固定返回 `eBonus=8888`,promotion 列表走专用 fixture,`playerpromotion/redeem` 固定复现 `Prize definition not found` 失败场景。
3. `80010852` - Task 10852 专用复现号。
开启 `MOCK_TASK_10852_ENABLED=true` 后,会员资料固定返回 `eBonus=188`,promotion 列表走专用 fixture,并强制提供可点击的 entitled 双 outcome 场景,用于验证多 outcome redeem。
4. `80010991` - 完整链路 / 同 outcome 切换场景号。
命中专用 `promotions.capture.80010991.json`,内含单 outcome reprint chain 和 3-outcome `USER_CHOICE` promotion;也用于 runtime fulfillment override,方便在 UI 上反复验证同一个 outcome 的 `Open Item / Auto Settle` 切换。
5. `100000059` - redeemed promotion detail 专用号。
命中 `award.promotions.100000059.json`,用于 `redeemedpromotion/detail` 返回账户级已兑 promotion 明细。
以下号码也出现在 `Mock_Gateway` 中,但更适合视为默认模板 / 示例数据,不计入上面的“特别会员号”:
1. `800048718` - 默认 promotion 抓包模板来源。
没有专属定向逻辑,未命中其他专用场景时,普通账号会回落到这份默认 promotion fixture。
2. `800049052` - 默认 redeemed promotions 示例号。
只在 `redeemedpromotion/detail` 没传账号且没有账户级记录时,作为默认示例数据中的 `customerId` 出现。
800048718 老会员----换新账号----910700001