# LSFX Mock 大额交易命中样本设计

## 背景

当前 `lsfx-mock-server` 的银行流水接口会返回完全随机的流水数据，但后端银行流水打标中的大额交易模型依赖摘要关键词、收支方向、金额阈值、交易日期，以及 `cretNo` 与员工/家属身份关系的匹配。仅有随机金额和随机摘要不足以稳定命中后端规则，导致联调时即使接口返回成功，后端打标结果仍可能为空。

本设计用于调整 Mock 流水生成策略，使其在保留随机噪声数据的同时，稳定产出可命中后端大额交易 8 条规则的样本流水。

## 目标

- 更新 `lsfx-mock-server` 的银行流水生成逻辑。
- 每个 `logId` 首次生成流水时，稳定包含可命中大额交易 8 条规则的样本。
- 在命中样本之外继续混入普通随机流水，保持 Mock 数据的随机感和分页场景。
- 不修改后端打标实现，以后端现有 SQL 口径作为唯一准绳。

## 范围

### In Scope

- `lsfx-mock-server` 获取银行流水接口的生成逻辑。
- 大额交易 8 条规则所需的命中样本模板。
- 对应的 Mock 单元测试与接口测试。
- 本次改动的实施记录文档。

### Out of Scope

- 后端 `CcdiBankTagAnalysisMapper.xml` 或打标 Service 逻辑调整。
- 其他模型组规则的 Mock 命中样本。
- Mock 服务接入主系统数据库或动态读取后端参数。

## 后端规则现状

后端当前已实际实现并可命中的大额交易规则为：

1. `HOUSE_OR_CAR_EXPENSE`
2. `TAX_EXPENSE`
3. `SINGLE_LARGE_INCOME`
4. `CUMULATIVE_INCOME`
5. `ANNUAL_TURNOVER`
6. `LARGE_CASH_DEPOSIT`
7. `FREQUENT_CASH_DEPOSIT`
8. `LARGE_TRANSFER`

这些规则的关键命中条件总结如下：

- 房车消费、税务支出：依赖 `userMemo` 或 `customerName` 的关键词命中，且 `drAmount > 0`。
- 单笔大额收入、累计收入、年流水、大额转账：依赖员工身份、对手方名称、收支方向、阈值及排除条件。
- 大额存现、单日多次存现：依赖 `cashType`、`userMemo`、`customerName` 与 `crAmount` 的联合条件。
- 多条规则要求 `cretNo` 能在后端库中关联到员工或家属，否则规则不会命中。

## 关键前提

Mock 必须复用一组后端环境中真实可识别的身份证号，否则仅靠金额和摘要无法满足后端 `exists staff/relation` 条件。

本次默认复用现有文档中已用于大额交易验证的身份池：

- 员工：`330101198801010011`
- 家属：`330101199001010022`
- 员工：`330101198802020033`
- 家属：`330101199202020044`

这些身份已在既有大额交易验证文档与种子 SQL 中使用，可作为 Mock 默认命中身份池。若后续目标环境不存在这些身份，需要在样本配置中同步替换。

## 设计概览

将现有“逐条完全随机生成”的策略调整为“两段式生成”：

1. 先生成固定数量的规则命中样本。
2. 再补充普通随机噪声流水。
3. 合并后统一排序/洗牌，写入当前 `logId` 缓存。
4. 分页接口继续基于缓存返回，保证同一 `logId` 多次请求结果一致。

## 组件设计

### 1. 普通随机流水生成器

保留现有随机生成能力，继续负责生成非命中噪声数据。其职责仅限于提供分页场景和背景数据，不承担命中保障。

### 2. 大额交易样本生成器

新增专用样本生成层，负责生成 8 条规则所需的流水组合。建议拆为独立模块，例如：

- `services/statement_rule_samples.py`

该模块维护：

- 默认身份池
- 默认阈值常量
- 每条规则的样本构造函数
- 公共流水字段构造辅助函数

### 3. 汇总与缓存层

`statement_service.py` 负责：

- 调用大额交易样本生成器获取命中样本
- 生成指定数量的噪声流水
- 为所有记录补齐唯一 `bankStatementId`、`bankTrxNumber`、`uploadSequnceNumber`
- 合并、打乱顺序并缓存
- 按页返回 `bankStatementList`

## 样本组织方案

为避免只为单一规则生成孤立流水，8 条规则拆为 5 组样本簇：

### A. 房车消费支出样本

- 1 至 2 条支出流水
- `drAmount > 0`
- `userMemo` 含 `购买房产首付款`、`购车首付款` 等关键词
- 或 `customerName` 命中 `房地产`、`贝壳`、`汽车销售`、`4S店` 等关键词
- `cretNo` 使用员工或家属身份证

### B. 税务支出样本

- 1 至 2 条支出流水
- `drAmount > 0`
- `userMemo` 或 `customerName` 命中 `税务`、`税款`、`税务局`、`国库`
- `cretNo` 使用员工或家属身份证

### C. 大额收入样本簇

使用同一员工身份证与同一非亲属对手方生成多条收入流水，复用命中：

- `SINGLE_LARGE_INCOME`
- `CUMULATIVE_INCOME`
- `ANNUAL_TURNOVER`

约束如下：

- 至少 1 条 `crAmount` 大于 `SINGLE_TRANSACTION_AMOUNT`
- 多条累计 `crAmount` 大于 `CUMULATIVE_TRANSACTION_AMOUNT`
- 再叠加大额收入/支出，使近一年累计交易额大于 `ANNUAL_TURNOVER`
- `leName != customerName`
- `customerName` 不得映射为该员工家属名称
- 避开工资排除条件，不能使用 `浙江兰溪农村商业银行股份有限公司`，`userMemo` 也不得含 `代发`、`工资`、`奖金`、`薪酬` 等词

### D. 大额存现样本簇

使用同一身份证、同一天生成 6 条现金存入流水，复用命中：

- `LARGE_CASH_DEPOSIT`
- `FREQUENT_CASH_DEPOSIT`

约束如下：

- 每条 `crAmount` 大于 `LARGE_CASH_DEPOSIT`
- 同日条数大于 `FREQUENT_CASH_DEPOSIT`
- `cashType` / `userMemo` / `customerName` 的组合需满足后端 `cashDepositPredicate`
- 推荐使用 `现金存款`、`ATM现金存款`、`自助存款现金存入`、`CRS存款`、`本行ATM存款` 等摘要

### E. 大额转账支出样本

- 1 至 2 条支出流水
- `drAmount > FREQUENT_TRANSFER`
- `userMemo` 含 `手机银行转账`、`对外转账`
- 或 `cashType` / `customerName` 含转账特征
- `userMemo` 不能包含 `款`，避免被后端排除
- `leName != customerName`

## 默认阈值策略

Mock 不接主系统数据库，因此不动态读取项目参数。为保证命中稳定，样本生成器内置与当前系统默认参数一致的阈值常量：

- `SINGLE_TRANSACTION_AMOUNT = 1111`
- `CUMULATIVE_TRANSACTION_AMOUNT = 50000001`
- `ANNUAL_TURNOVER = 50000001`
- `LARGE_CASH_DEPOSIT = 2000001`
- `FREQUENT_CASH_DEPOSIT = 5`
- `FREQUENT_TRANSFER = 100001`

样本金额应显著高于阈值，避免边界值因格式化或比较方式差异导致误判。

## 数据生成细节

### 字段稳定要求

以下字段不得继续完全随机：

- `cretNo`
- `leName`
- `customerName`
- `userMemo`
- `cashType`
- `trxDate`
- `crAmount`
- `drAmount`

它们需要按规则模板构造。

### 可以继续随机的字段

以下字段可保留随机生成或在模板基础上随机化：

- `accountMaskNo`
- `customerAccountMaskNo`
- `bankTrxNumber`
- `balanceAmount`
- `bank`
- `customerBank`
- `uploadSequnceNumber`

### 日期策略

- `ANNUAL_TURNOVER` 相关样本统一放在当前日期前 12 个月内。
- `FREQUENT_CASH_DEPOSIT` 相关样本统一放在同一天但不同时间点。
- 其他样本可分布在近一年内，避免全部集中到同一时刻。

### 总量策略

- 继续沿用当前 `1200-1500` 的总条数范围。
- 先生成全部命中样本，再以 `totalCount - sampleCount` 的差值补足噪声流水。
- 若后续命中样本数量增长超过随机总量下限，应自动以命中样本数作为最小总量，避免截断命中数据。

### 排序与分页

生成完成后统一打乱顺序，再根据请求分页返回。这样：

- 前端仍能看到类似真实的随机顺序
- 同一 `logId` 由于缓存存在，重复请求时顺序稳定

## 错误处理

- 若大额交易样本构造失败，直接抛出明确异常，不静默降级为纯随机流水。
- 这样能避免接口返回正常但后端永远打不中的隐性问题。
- 不新增复杂容错或回退机制，保持 Mock 行为可预测。

## 测试设计

至少补充两类验证：

### 1. 样本生成测试

验证大额交易样本生成器输出满足关键特征：

- 存在房车消费关键词支出
- 存在税务关键词支出
- 存在单笔超阈值收入
- 存在同一对手方累计超阈值收入
- 存在近一年累计交易额超阈值样本
- 存在同日 6 笔以上现金存入
- 存在单笔存现超阈值
- 存在单笔转账支出超阈值且摘要不含 `款`

### 2. 接口返回测试

调用 `getBSByLogId`，验证：

- 返回总数正常
- `bankStatementList` 中能找到各类命中样本特征
- 同一 `logId` 多次请求返回相同数据
- 分页拼接后的全量结果仍包含全部命中样本

## 成功标准

- Mock 每次首次生成流水时都稳定包含大额交易 8 条规则所需样本。
- 同一 `logId` 多次分页请求数据一致。
- 在默认身份池存在于目标环境的前提下，后端接入 Mock 返回数据后，现有大额交易 8 条规则可以被正确命中。
- 普通随机噪声流水仍然存在，不退化为完全固定数据集。

## 风险与约束

- 默认身份池依赖后端环境已有对应员工/家属数据；若环境不一致，需要替换身份池常量。
- Mock 使用内置阈值，若后端系统默认参数未来变更，Mock 也需要同步更新。
- 若后端 SQL 规则继续演进，本设计中的样本关键词和排除词也要同步校准。

## 实施输出

实施阶段应至少产出：

- Mock 代码改动
- 对应测试用例
- 一份前端实施计划
- 一份后端实施计划
- 一份实施记录文档

其中前后端实施计划用于说明联调影响面：本次主要改动在 Mock 服务，但后端计划中需要明确验证路径和命中校验方式。
