# 流水与对账 - PRD

## 文档信息

| 项目 | 内容 |
|------|------|
| 文档版本 | v1.1 |
| 创建日期 | 2026-02-26 |
| 模块名称 | 流水与对账 |
| 文档状态 | 已评审修订 |

---

## 一、模块概述

### 1.1 模块定位

流水与对账模块负责支付流水的查询和对账管理。支付流水来源于支付订单(payment_order),对账功能用于核对支付中台数据与服务商数据是否一致,及时发现和处理差异。

### 1.2 核心功能

1. **支付流水查询** - 查询所有支付交易流水,支持多维度筛选和导出
2. **对账单管理** - 下载服务商对账单,进行简单匹配对账
3. **差异处理** - 展示对账差异,支持人工标记处理结果

### 1.3 MVP版本范围

本模块MVP版本提供基础对账能力:
- ✅ 手动下载对账单
- ✅ 自动下载对账单 (v1.1.2新增)
- ✅ 自动解析对账文件
- ✅ 简单匹配 (按服务商订单号匹配)
- ✅ 展示差异列表
- ❌ 暂不支持自动调账
- ❌ 暂不支持复杂规则匹配

### 1.4 使用角色

- **财务人员** - 下载对账单、查看对账结果、处理差异
- **运营平台管理员** - 查看支付流水、导出数据
- **系统定时任务** - 定期触发对账任务 (后续版本)

---

## 二、功能详细说明

### 2.1 支付流水查询

#### 2.1.1 功能描述

支付流水即支付订单(payment_order表),提供多维度查询和导出功能,方便财务人员和管理员查看交易明细。

#### 2.1.2 查询条件

| 查询条件 | 类型 | 说明 |
|---------|------|------|
| 订单号 | 文本框 | 支持支付中台订单号、业务订单号、服务商订单号模糊查询 |
| 小区 | 下拉多选 | 选择一个或多个小区 |
| 业务类型 | 下拉多选 | 物业费/停车费/商城/专项服务/增值服务 |
| 支付服务商 | 下拉多选 | 微信/支付宝/易宝等 |
| 支付方式 | 下拉多选 | 扫码/H5/公众号/托收等 |
| 订单状态 | 下拉多选 | 待支付/已支付/已关闭/已退款/部分退款 |
| 支付时间 | 日期范围 | 选择开始时间和结束时间 |
| 创建时间 | 日期范围 | 选择开始时间和结束时间 |

#### 2.1.3 列表展示

**列表字段:**

| 字段 | 说明 |
|------|------|
| 支付中台订单号 | platform_order_no |
| 业务订单号 | business_order_no |
| 小区名称 | 通过community_id关联获取 |
| 业务类型 | 中文显示:物业费/停车费等 |
| 订单金额 | 显示为元,保留2位小数 |
| 实付金额 | 显示为元,保留2位小数 |
| 退款金额 | 显示为元,保留2位小数 |
| 手续费 | 显示为元,保留2位小数 |
| 支付服务商 | 显示服务商名称 |
| 支付方式 | 显示支付方式名称 |
| 订单状态 | 中文显示+状态颜色标识 |
| 支付时间 | YYYY-MM-DD HH:mm:ss |
| 创建时间 | YYYY-MM-DD HH:mm:ss |
| 操作 | 查看详情 |

**订单状态映射 (v1.1统一):**

| 数据库值 | 页面显示 | 颜色标识 |
|---------|---------|---------|
| pending | 待支付 | 蓝色 |
| paid | 已支付 | 绿色 |
| closed | 已关闭 | 灰色 |
| part_refunded | 部分退款 | 黄色 |
| refunded | 已退款 | 橙色 |

**说明:**
- 数据库存储使用英文枚举值 (pending/paid/closed/part_refunded/refunded)
- 页面展示时映射为中文,并使用颜色标识

#### 2.1.4 流水详情

点击"查看详情"展示完整订单信息:

**基础信息区**
- 支付中台订单号
- 业务订单号
- 服务商订单号
- 服务商交易流水号

**金额信息区**
- 订单金额
- 实付金额
- 手续费
- 已退款金额
- 可退金额

**业务信息区**
- 小区名称
- 业务类型
- 用户ID
- 订单描述

**支付信息区**
- 支付服务商
- 支付方式
- 业务场景
- 签约协议号 (如有)

**时间信息区**
- 创建时间
- 支付时间
- 关闭时间 (如有)

**退款记录区** (如有退款)
- 展示该订单的所有退款记录
- 显示:退款单号、退款金额、退款状态、退款时间

#### 2.1.5 导出功能

**导出格式:** Excel (.xlsx)

**导出字段:**
- 支付中台订单号
- 业务订单号
- 服务商订单号
- 服务商交易流水号
- 小区名称
- 业务类型
- 订单金额
- 实付金额
- 手续费
- 退款金额
- 支付服务商
- 支付方式
- 订单状态
- 支付时间
- 创建时间

**导出限制:**
- 单次最多导出10000条
- 超过10000条提示分批导出

**文件命名:**
`支付流水_{开始日期}_{结束日期}_{时间戳}.xlsx`

例如: `支付流水_20260201_20260228_20260225103000.xlsx`

---

### 2.2 对账单管理

#### 2.2.1 功能描述

对账是核对支付中台数据与服务商数据是否一致的过程。通过下载服务商对账单,与本地支付流水进行匹配,发现并处理差异。

#### 2.2.2 对账流程

```
财务人员
  │
  ├─ 1. 进入"对账单管理"页面
  │
  ├─ 2. 选择对账参数
  │    ├─ 支付服务商
  │    └─ 对账日期 (选择需要对账的日期,如:2026-02-24)
  │
  ├─ 3. 点击"下载对账单"按钮
  │
  ▼
支付中台 - 对账处理
  │
  ├─ 4. 调用服务商对账单接口
  │    └─ 传递对账日期
  │
  ├─ 5. 下载对账文件
  │    ├─ 微信:CSV格式
  │    ├─ 支付宝:CSV格式
  │    └─ 易宝:Excel格式
  │
  ├─ 6. 保存对账单记录
  │    ├─ 下载状态: success
  │    ├─ 文件路径: /reconciliation/WECHAT/20260224.csv
  │    └─ 对账状态: not_start (未开始对账)
  │
  ├─ 7. 返回下载结果
  │
  ▼
财务人员
  │
  ├─ 8. 点击"开始对账"按钮
  │
  ▼
支付中台 - 对账匹配
  │
  ├─ 9. 解析对账文件
  │    └─ 提取: 服务商订单号、交易金额、手续费、交易时间
  │
  ├─ 10. 查询本地流水
  │     └─ 查询对账日期的所有支付订单 (按支付时间)
  │
  ├─ 11. 简单匹配逻辑
  │     ├─ 按服务商订单号(provider_order_no)匹配
  │     ├─ 匹配成功: match_count++
  │     └─ 匹配失败: 记录差异
  │
  ├─ 12. 差异分类
  │     ├─ 长款 (long_money): 服务商有,系统无
  │     ├─ 短款 (short_money): 系统有,服务商无
  │     └─ 金额差异 (amount_diff): 订单号匹配,但金额不一致
  │
  ├─ 13. 生成对账结果
  │     ├─ 交易总笔数: 100
  │     ├─ 交易总金额: 500000分
  │     ├─ 匹配笔数: 95
  │     ├─ 差异笔数: 5
  │     └─ 对账状态: completed
  │
  ├─ 14. 保存对账差异记录
  │     └─ 每条差异保存一条记录
  │
  ▼
财务人员
  │
  └─ 15. 查看对账结果和差异明细
```

#### 2.2.3 对账规则 (MVP版本)

**匹配规则:**
- 按服务商订单号(provider_order_no)进行一对一匹配
- 匹配成功条件:
  - 服务商订单号完全一致
  - 交易金额一致 (允许误差±1分,处理浮点数精度问题)

**差异类型:**

| 差异类型 | 代码 | 说明 |
|---------|------|------|
| 长款 | long_money | 服务商对账单有该交易,支付中台无记录 |
| 短款 | short_money | 支付中台有该交易,服务商对账单无记录 |
| 金额差异 | amount_diff | 订单号匹配,但金额不一致 |

**差异原因分析:**
- 长款原因:
  - 回调丢失 (服务商回调失败,支付中台未收到)
  - 数据延迟 (对账单已生成,但回调还未到)

- 短款原因:
  - 用户已下单但未支付
  - 订单已关闭
  - 数据同步延迟

- 金额差异原因:
  - 数据错误 (极少发生)
  - 手续费处理差异

#### 2.2.4 页面交互

**对账单列表页**

**列表字段:**
- 对账日期
- 支付服务商
- 下载状态 (成功/失败)
- 下载时间
- 对账状态 (未开始/对账中/已完成)
- 交易总笔数
- 交易总金额
- 匹配笔数
- 差异笔数
- 操作:查看详情、开始对账 (未开始时显示)、重新对账

**对账单详情页**

Tab1: 对账概况
- 对账基础信息
  - 对账日期
  - 支付服务商
  - 对账文件路径
  - 下载时间

- 对账结果统计
  - 服务商交易笔数
  - 服务商交易金额
  - 本地交易笔数
  - 本地交易金额
  - 匹配笔数
  - 差异笔数

Tab2: 对账差异
- 差异列表
  - 差异类型
  - 支付中台订单号
  - 服务商订单号
  - 本地金额
  - 服务商金额
  - 差异金额
  - 处理状态 (待处理/已处理)
  - 处理说明
  - 操作:标记已处理

#### 2.2.5 对账单自动下载 (v1.1.2新增)

**功能描述:**
系统定时自动下载各服务商的对账单，减少财务人员手动操作，确保对账及时性。

**定时任务设计:**

| 任务名称 | ReconciliationAutoDownloadJob |
|---------|------------------------------|
| 执行频率 | 每天凌晨3:00执行 |
| 对账日期 | T-1 (前一天) |
| 超时时间 | 30分钟 |

**执行流程:**
```
定时任务触发 (每天3:00)
  │
  ├─ 1. 查询所有启用的支付服务商
  │
  ├─ 2. 遍历服务商,依次下载对账单
  │    ├─ 调用服务商对账单接口
  │    ├─ 传递对账日期 (T-1)
  │    └─ 下载对账文件
  │
  ├─ 3. 保存对账单记录
  │    ├─ 下载成功: download_status = 'success'
  │    ├─ 下载失败: download_status = 'failed', 记录错误信息
  │    └─ 对账状态: not_start
  │
  ├─ 4. 下载完成后,可选自动触发对账 (可配置)
  │    └─ 配置项: auto_reconcile_after_download (默认false)
  │
  └─ 5. 发送下载结果通知
       ├─ 全部成功: 不通知
       ├─ 部分失败: 邮件/站内信通知财务人员
       └─ 全部失败: 邮件/站内信告警
```

**自动下载配置:**

| 配置项 | 说明 | 默认值 |
|-------|------|--------|
| enable_auto_download | 是否启用自动下载 | true |
| download_time | 下载执行时间 | 03:00 |
| retry_times | 下载失败重试次数 | 3 |
| retry_interval | 重试间隔(分钟) | 10 |
| auto_reconcile_after_download | 下载后自动对账 | false |
| notify_on_failure | 失败时通知 | true |

**页面配置入口:**
- 管理端 → 系统配置 → 对账设置 → 自动下载配置

**异常处理:**

| 异常场景 | 处理方式 |
|---------|---------|
| 服务商接口超时 | 自动重试,最多3次,每次间隔10分钟 |
| 服务商返回错误 | 记录错误信息,标记下载失败 |
| 对账单文件为空 | 记录为下载成功,对账时提示无数据 |
| 已存在当天记录 | 跳过下载,使用已有记录 |

**手动与自动的关系:**
- 自动下载不影响手动下载功能
- 若自动下载失败,财务人员可手动重新下载
- 手动下载会覆盖自动下载的记录(同一服务商同一天)

---

### 2.3 差异处理

#### 2.3.1 功能描述

对账发现差异后,财务人员可以查看差异明细,分析差异原因,并标记处理结果。

#### 2.3.2 差异处理完整流程 (v1.2.0增强)

**长款处理流程 (服务商有记录,本地无记录):**

```
财务人员发现长款
  │
  ├─ 1. 分析长款原因
  │    ├─ 回调丢失: 服务商已扣款但回调未到达
  │    ├─ 跨日订单: 订单支付时间跨日,归属不同对账日
  │    └─ 服务商数据错误: 服务商对账单有误
  │
  ├─ 2. 回调丢失处理
  │    ├─ 调用服务商订单查询接口确认支付状态
  │    ├─ 如果确认已支付:
  │    │    ├─ 点击"补录订单"按钮
  │    │    ├─ 填写补录信息:
  │    │    │    ├─ 业务订单号 (必填,从业务系统获取)
  │    │    │    ├─ 支付金额 (自动填充,不可修改)
  │    │    │    ├─ 支付时间 (自动填充)
  │    │    │    ├─ 用户ID (必填)
  │    │    │    └─ 补录原因 (必填)
  │    │    │
  │    │    ├─ 系统创建补录订单
  │    │    │    ├─ 状态直接设为 paid
  │    │    │    ├─ 标记 order_source = 'manual_supplement'
  │    │    │    └─ 关联差异记录ID
  │    │    │
  │    │    └─ 通知业务系统 (可选)
  │    │
  │    └─ 如果确认未支付或数据错误:
  │         ├─ 标记为"服务商数据异常"
  │         └─ 联系服务商处理
  │
  ├─ 3. 跨日订单处理
  │    ├─ 确认订单在其他对账日已匹配
  │    ├─ 标记处理结果: "跨日订单,已在[日期]对账单中匹配"
  │    └─ 关联对应对账记录ID
  │
  └─ 4. 更新差异处理状态
       ├─ handle_status = 'handled'
       ├─ handle_type = 'supplement' / 'cross_day' / 'provider_error'
       ├─ handle_remark = 处理说明
       └─ handle_time = NOW()
```

**短款处理流程 (本地有记录,服务商无记录):**

```
财务人员发现短款
  │
  ├─ 1. 分析短款原因
  │    ├─ 订单未支付: 用户未完成支付,正常情况
  │    ├─ 跨日结算: 支付成功但服务商次日结算
  │    ├─ 数据同步延迟: 服务商对账单生成延迟
  │    └─ 本地数据错误: 系统错误记录了不存在的支付
  │
  ├─ 2. 订单未支付处理
  │    ├─ 检查订单状态:
  │    │    ├─ pending: 正常,无需处理
  │    │    ├─ closed: 正常,超时关闭
  │    │    └─ paid: 异常,需进一步核查
  │    │
  │    └─ 标记处理结果: "订单未支付,正常"
  │
  ├─ 3. 跨日结算处理
  │    ├─ 等待次日对账单确认
  │    ├─ 如果次日对账单有该记录: 标记"跨日结算,已确认"
  │    └─ 如果次日仍无: 联系服务商核实
  │
  ├─ 4. 本地数据错误处理
  │    ├─ 确认是否为重复订单或测试订单
  │    ├─ 如需调整:
  │    │    ├─ 记录调整原因
  │    │    ├─ 更新订单状态 (需审批)
  │    │    └─ 记录操作日志
  │    │
  │    └─ 标记处理结果
  │
  └─ 5. 更新差异处理状态
```

**金额差异处理流程:**

```
财务人员发现金额差异
  │
  ├─ 1. 分析差异原因
  │    ├─ 手续费计算: 服务商扣除手续费后金额
  │    ├─ 汇率波动: 跨境支付汇率差异
  │    ├─ 优惠/补贴: 服务商营销活动导致
  │    └─ 数据错误: 一方数据记录错误
  │
  ├─ 2. 手续费差异处理
  │    ├─ 差异金额 ≤ 手续费: 正常
  │    │    └─ 标记: "手续费差异,已核对"
  │    │
  │    └─ 差异金额 > 手续费: 异常
  │         └─ 需进一步核查
  │
  ├─ 3. 数据调整 (需审批)
  │    ├─ 发起调账申请
  │    │    ├─ 原金额
  │    │    ├─ 调整后金额
  │    │    ├─ 调整原因 (必填)
  │    │    └─ 附件凭证 (可选)
  │    │
  │    ├─ 审批流程 (见2.3.5)
  │    │
  │    └─ 审批通过后执行调账
  │         ├─ 更新订单金额
  │         ├─ 记录调账流水
  │         └─ 标记差异处理完成
  │
  └─ 4. 更新差异处理状态
```

#### 2.3.3 处理状态

| 状态 | 代码 | 说明 |
|------|------|------|
| 待处理 | pending | 发现差异,尚未处理 |
| 处理中 | processing | 正在处理或等待审批 |
| 已处理 | handled | 财务已核实并标记处理结果 |
| 已忽略 | ignored | 确认为正常差异,忽略处理 |

#### 2.3.4 处理类型 (v1.2.0新增)

| 处理类型 | 代码 | 说明 |
|---------|------|------|
| 补录订单 | supplement | 长款-回调丢失,补录订单 |
| 跨日匹配 | cross_day | 跨日订单,在其他日期匹配 |
| 正常差异 | normal | 手续费/汇率等正常差异 |
| 调账处理 | adjustment | 金额调整 |
| 服务商错误 | provider_error | 服务商数据错误 |
| 系统错误 | system_error | 本地系统数据错误 |
| 忽略处理 | ignore | 确认忽略 |

#### 2.3.5 调账审批流程 (v1.2.0新增)

**适用场景：**
- 金额差异需要调整订单金额
- 需要作废或修正错误订单
- 退款金额与实际不符需调整

**审批规则：**
| 调账金额 | 审批级别 | 审批人 |
|---------|---------|--------|
| ≤ 1000元 | 一级审批 | 财务主管 |
| 1000-10000元 | 二级审批 | 财务经理 |
| > 10000元 | 三级审批 | 财务总监 |

**审批流程：**
```
财务人员发起调账申请
  │
  ├─ 1. 填写调账信息
  │    ├─ 订单号
  │    ├─ 调账类型: 金额修正/订单作废/退款修正
  │    ├─ 原金额
  │    ├─ 调整后金额
  │    ├─ 调账原因 (必填)
  │    └─ 附件凭证 (服务商截图等)
  │
  ├─ 2. 系统判断审批级别
  │    └─ 根据调账金额匹配审批规则
  │
  ├─ 3. 提交审批
  │    ├─ 发送审批通知给审批人
  │    └─ 状态: 待审批
  │
  ├─ 4. 审批人处理
  │    ├─ 审批通过: 执行调账操作
  │    │    ├─ 更新订单/退款金额
  │    │    ├─ 记录调账流水
  │    │    └─ 更新差异处理状态
  │    │
  │    └─ 审批拒绝: 退回申请
  │         ├─ 填写拒绝原因
  │         └─ 通知发起人
  │
  └─ 5. 记录审批日志
       └─ 完整记录审批过程
```

**调账记录表 (payment_adjustment_record):**

| 字段名 | 类型 | 说明 |
|-------|------|------|
| id | BIGINT | 主键ID |
| platform_order_no | VARCHAR(64) | 订单号 |
| adjustment_type | VARCHAR(20) | 调账类型 |
| original_amount | BIGINT | 原金额 |
| adjusted_amount | BIGINT | 调整后金额 |
| diff_amount | BIGINT | 差异金额 |
| adjustment_reason | VARCHAR(500) | 调账原因 |
| attachment_url | VARCHAR(255) | 附件地址 |
| approval_status | VARCHAR(20) | 审批状态 |
| approver_id | BIGINT | 审批人ID |
| approval_time | DATETIME | 审批时间 |
| approval_remark | VARCHAR(500) | 审批备注 |
| applicant_id | BIGINT | 申请人ID |
| created_at | DATETIME | 创建时间 |

#### 2.3.6 页面交互

**差异列表页**
- 筛选条件:
  - 差异类型
  - 处理状态
- 批量操作:
  - 批量标记已处理
- 单条操作:
  - 标记已处理
  - 查看详情

**标记已处理弹窗**
- 处理说明 (必填,文本域,最多500字)
- 确定 / 取消

---

## 三、数据库设计

### 3.1 对账单表 (payment_reconciliation)

#### 3.1.1 表说明
存储对账单信息和对账结果

#### 3.1.2 字段设计

| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|-------|------|------|-------|-------|------|
| id | BIGINT | - | 否 | 自增 | 主键ID |
| provider_id | BIGINT | - | 否 | - | 支付服务商ID,外键关联payment_provider.id |
| bill_date | DATE | - | 否 | - | 账单日期 (对账的日期,如:2026-02-24) |
| download_status | VARCHAR | 20 | 否 | pending | 下载状态:pending/success/failed |
| download_time | DATETIME | - | 是 | NULL | 下载时间 |
| file_path | VARCHAR | 255 | 是 | NULL | 对账文件路径 |
| total_count | INT | - | 否 | 0 | 服务商交易总笔数 |
| total_amount | BIGINT | - | 否 | 0 | 服务商交易总金额 (分) |
| local_count | INT | - | 否 | 0 | 本地交易总笔数 |
| local_amount | BIGINT | - | 否 | 0 | 本地交易总金额 (分) |
| reconcile_status | VARCHAR | 20 | 否 | not_start | 对账状态:not_start/processing/completed |
| match_count | INT | - | 否 | 0 | 匹配笔数 |
| diff_count | INT | - | 否 | 0 | 差异笔数 |
| reconcile_time | DATETIME | - | 是 | NULL | 对账完成时间 |
| created_at | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_at | DATETIME | - | 否 | CURRENT_TIMESTAMP ON UPDATE | 更新时间 |
| remark | VARCHAR | 500 | 是 | NULL | 备注 |

#### 3.1.3 索引设计

| 索引名 | 索引类型 | 字段 | 说明 |
|-------|---------|------|------|
| PRIMARY | 主键 | id | 主键索引 |
| uk_provider_bill_date | 唯一索引 | provider_id, bill_date | 同一服务商同一天只能有一条对账记录 |
| idx_provider_id | 普通索引 | provider_id | 服务商查询 |
| idx_bill_date | 普通索引 | bill_date | 日期查询 |
| idx_reconcile_status | 普通索引 | reconcile_status | 状态查询 |

#### 3.1.4 外键约束

```sql
ALTER TABLE payment_reconciliation
ADD CONSTRAINT fk_reconciliation_provider
FOREIGN KEY (provider_id) REFERENCES payment_provider(id)
ON DELETE RESTRICT ON UPDATE CASCADE;
```

#### 3.1.5 示例数据

```sql
INSERT INTO payment_reconciliation (provider_id, bill_date, download_status, download_time, file_path, total_count, total_amount, local_count, local_amount, reconcile_status, match_count, diff_count, reconcile_time, created_at) VALUES
-- =============================================
-- 微信支付对账 (provider_id=1)
-- =============================================
-- 已完成对账 - 有差异
('2026-02-24', 1, 'success', '2026-02-25 09:00:00', '/reconciliation/WECHAT/20260224.csv', 156, 1250000, 156, 1249500, 'completed', 151, 5, '2026-02-25 09:15:00', '2026-02-25 09:00:00'),
('2026-02-25', 1, 'success', '2026-02-26 09:00:00', '/reconciliation/WECHAT/20260225.csv', 203, 1680000, 203, 1680000, 'completed', 203, 0, '2026-02-26 09:10:00', '2026-02-26 09:00:00'),
('2026-02-26', 1, 'success', '2026-02-27 09:00:00', '/reconciliation/WECHAT/20260226.csv', 189, 1520000, 189, 1519700, 'completed', 186, 3, '2026-02-27 09:12:00', '2026-02-27 09:00:00'),
('2026-02-27', 1, 'success', '2026-02-28 09:00:00', '/reconciliation/WECHAT/20260227.csv', 175, 1420000, 175, 1420000, 'completed', 175, 0, '2026-02-28 09:08:00', '2026-02-28 09:00:00'),
-- 等待对账
('2026-03-05', 1, 'success', '2026-03-06 09:00:00', '/reconciliation/WECHAT/20260305.csv', 198, 1590000, 198, 1590000, 'not_start', 0, 0, NULL, '2026-03-06 09:00:00'),

-- =============================================
-- 支付宝对账 (provider_id=2)
-- =============================================
('2026-02-24', 2, 'success', '2026-02-25 09:30:00', '/reconciliation/ALIPAY/20260224.csv', 89, 720000, 89, 720000, 'completed', 89, 0, '2026-02-25 09:45:00', '2026-02-25 09:30:00'),
('2026-02-25', 2, 'success', '2026-02-26 09:30:00', '/reconciliation/ALIPAY/20260225.csv', 112, 890000, 112, 889500, 'completed', 110, 2, '2026-02-26 09:50:00', '2026-02-26 09:30:00'),
('2026-02-26', 2, 'success', '2026-02-27 09:30:00', '/reconciliation/ALIPAY/20260226.csv', 95, 780000, 95, 780000, 'completed', 95, 0, '2026-02-27 09:42:00', '2026-02-27 09:30:00'),
-- 对账中
('2026-03-05', 2, 'success', '2026-03-06 09:30:00', '/reconciliation/ALIPAY/20260305.csv', 108, 850000, 108, 850000, 'processing', 50, 0, NULL, '2026-03-06 09:30:00'),

-- =============================================
-- 易宝托收对账 (provider_id=3)
-- =============================================
('2026-02-24', 3, 'success', '2026-02-25 10:00:00', '/reconciliation/YEEPAY/20260224.csv', 45, 2250000, 45, 2250000, 'completed', 45, 0, '2026-02-25 10:20:00', '2026-02-25 10:00:00'),
('2026-03-01', 3, 'success', '2026-03-02 10:00:00', '/reconciliation/YEEPAY/20260301.csv', 120, 6000000, 120, 5998500, 'completed', 118, 2, '2026-03-02 10:30:00', '2026-03-02 10:00:00'),

-- =============================================
-- 银联支付对账 (provider_id=4)
-- =============================================
('2026-02-27', 4, 'success', '2026-02-28 10:00:00', '/reconciliation/UNIONPAY/20260227.csv', 23, 89000, 23, 89000, 'completed', 23, 0, '2026-02-28 10:15:00', '2026-02-28 10:00:00'),

-- =============================================
-- 下载失败的对账单
-- =============================================
('2026-03-04', 1, 'failed', NULL, NULL, 0, 0, 0, 0, 'not_start', 0, 0, NULL, '2026-03-05 09:00:00'),

-- =============================================
-- 工商银行代收对账 (provider_id=6)
-- =============================================
('2026-02-28', 6, 'success', '2026-03-01 10:00:00', '/reconciliation/ICBC/20260228.csv', 15, 7500000, 15, 7500000, 'completed', 15, 0, '2026-03-01 10:25:00', '2026-03-01 10:00:00');
```

---

### 3.2 对账差异表 (payment_reconciliation_diff)

#### 3.2.1 表说明
存储对账差异明细

#### 3.2.2 字段设计

| 字段名 | 类型 | 长度 | 允许空 | 默认值 | 说明 |
|-------|------|------|-------|-------|------|
| id | BIGINT | - | 否 | 自增 | 主键ID |
| reconciliation_id | BIGINT | - | 否 | - | 对账单ID,外键关联payment_reconciliation.id |
| diff_type | VARCHAR | 20 | 否 | - | 差异类型:long_money/short_money/amount_diff |
| platform_order_no | VARCHAR | 64 | 是 | NULL | 支付中台订单号 (短款时为空) |
| provider_order_no | VARCHAR | 128 | 否 | - | 服务商订单号 |
| platform_amount | BIGINT | - | 否 | 0 | 本地金额 (分,短款时为0) |
| provider_amount | BIGINT | - | 否 | 0 | 服务商金额 (分,长款时为0) |
| diff_amount | BIGINT | - | 否 | 0 | 差异金额 (分) |
| handle_status | VARCHAR | 20 | 否 | pending | 处理状态:pending/handled |
| handle_remark | VARCHAR | 500 | 是 | NULL | 处理说明 |
| handle_time | DATETIME | - | 是 | NULL | 处理时间 |
| created_at | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 |
| updated_at | DATETIME | - | 否 | CURRENT_TIMESTAMP ON UPDATE | 更新时间 |
| remark | VARCHAR | 500 | 是 | NULL | 备注 |

#### 3.2.3 索引设计

| 索引名 | 索引类型 | 字段 | 说明 |
|-------|---------|------|------|
| PRIMARY | 主键 | id | 主键索引 |
| idx_reconciliation_id | 普通索引 | reconciliation_id | 对账单查询 |
| idx_reconcile_type_status | 复合索引 | reconciliation_id, diff_type, handle_status | 按对账单+差异类型+处理状态查询 (v1.1新增) |
| idx_platform_order_no | 普通索引 | platform_order_no | 订单号查询 |
| idx_provider_order_no | 普通索引 | provider_order_no | 服务商订单号查询 |
| idx_diff_type | 普通索引 | diff_type | 差异类型查询 |
| idx_handle_status | 普通索引 | handle_status | 处理状态查询 |

**索引调整说明 (v1.1):**
- **新增**: idx_reconcile_type_status (对账单ID+差异类型+处理状态复合索引)
- **用途**: 优化差异列表查询性能,常用于按对账单ID查询特定类型或状态的差异

#### 3.2.4 外键约束

```sql
ALTER TABLE payment_reconciliation_diff
ADD CONSTRAINT fk_diff_reconciliation
FOREIGN KEY (reconciliation_id) REFERENCES payment_reconciliation(id)
ON DELETE CASCADE ON UPDATE CASCADE;
```

#### 3.2.5 示例数据

```sql
INSERT INTO payment_reconciliation_diff (reconciliation_id, diff_type, platform_order_no, provider_order_no, platform_amount, provider_amount, diff_amount, handle_status, handle_remark, handle_time, created_at) VALUES
-- =============================================
-- 对账单1 (2026-02-24微信) 的差异
-- =============================================
-- 长款: 服务商有记录,本地无记录
(1, 'long_money', NULL, 'WX_MISS_001', 0, 15000, 15000, 'handled', '确认为跨日订单,已在次日对账单中匹配', '2026-02-25 14:00:00', '2026-02-25 09:15:00'),
(1, 'long_money', NULL, 'WX_MISS_002', 0, 8000, 8000, 'pending', NULL, NULL, '2026-02-25 09:15:00'),
-- 短款: 本地有记录,服务商无记录
(1, 'short_money', 'PAY20260224100001010', 'WX_LOCAL_001', 5000, 0, 5000, 'handled', '确认为延迟结算,服务商次日到账', '2026-02-25 15:00:00', '2026-02-25 09:15:00'),
-- 金额不一致
(1, 'amount_diff', 'PAY20260224100001011', 'WX_AMOUNT_001', 10000, 10030, 30, 'handled', '手续费差异,已核对无误', '2026-02-25 16:00:00', '2026-02-25 09:15:00'),
(1, 'amount_diff', 'PAY20260224100001012', 'WX_AMOUNT_002', 25000, 24970, 30, 'pending', NULL, NULL, '2026-02-25 09:15:00'),

-- =============================================
-- 对账单3 (2026-02-26微信) 的差异
-- =============================================
(3, 'long_money', NULL, 'WX_MISS_003', 0, 12000, 12000, 'pending', NULL, NULL, '2026-02-27 09:12:00'),
(3, 'amount_diff', 'PAY20260226100003001', 'WX_AMOUNT_003', 120000, 120050, 50, 'handled', '手续费计算差异', '2026-02-27 14:00:00', '2026-02-27 09:12:00'),
(3, 'short_money', 'PAY20260226100003004', 'WX_LOCAL_002', 1500, 0, 1500, 'pending', NULL, NULL, '2026-02-27 09:12:00'),

-- =============================================
-- 对账单6 (2026-02-25支付宝) 的差异
-- =============================================
(6, 'amount_diff', 'PAY20260225100002002', 'ALI_AMOUNT_001', 36000, 35980, 20, 'handled', '汇率波动导致', '2026-02-26 15:00:00', '2026-02-26 09:50:00'),
(6, 'long_money', NULL, 'ALI_MISS_001', 0, 5500, 5500, 'pending', NULL, NULL, '2026-02-26 09:50:00'),

-- =============================================
-- 对账单11 (2026-03-01易宝托收) 的差异
-- =============================================
(11, 'short_money', 'PAY20260301100003003', 'YB_LOCAL_001', 240000, 0, 240000, 'handled', '托收延迟到账,T+1确认', '2026-03-02 16:00:00', '2026-03-02 10:30:00'),
(11, 'amount_diff', 'PAY20260301100007001', 'YB_AMOUNT_001', 50000, 49850, 150, 'pending', NULL, NULL, '2026-03-02 10:30:00');
```

---

## 四、数据迁移 (v1.0 → v1.1)

### 4.1 索引优化脚本

```sql
-- 新增对账差异表复合索引
ALTER TABLE payment_reconciliation_diff
ADD INDEX idx_reconcile_type_status (reconciliation_id, diff_type, handle_status);
```

### 4.2 数据验证

```sql
-- 验证索引是否创建成功
SHOW INDEX FROM payment_reconciliation_diff WHERE Key_name = 'idx_reconcile_type_status';
```

---

## 五、业务流程

### 5.1 完整对账流程图

```
财务人员选择对账日期和服务商
  ↓
点击"下载对账单"
  ↓
调用服务商对账单接口
  ↓
下载对账文件并保存
  ↓
创建对账单记录 (状态:not_start)
  ↓
财务人员点击"开始对账"
  ↓
解析对账文件
  ↓
查询本地支付流水
  ↓
按服务商订单号匹配
  ↓
生成对账结果和差异记录
  ↓
更新对账状态为 completed
  ↓
财务人员查看差异明细
  ↓
分析差异原因并处理
  ↓
标记差异处理结果
  ↓
对账完成
```

---

## 六、异常处理

### 6.1 对账异常

| 异常场景 | 处理方式 |
|---------|---------|
| 下载对账单失败 | 记录错误信息,提示用户重新下载 |
| 对账文件格式错误 | 提示"对账文件格式不正确,无法解析" |
| 对账文件为空 | 提示"对账文件无数据" |
| 重复对账 | 提示"该日期已对账,确认重新对账?" |
| 服务商接口超时 | 提示"服务商接口超时,请稍后重试" |

### 6.2 差异处理异常

| 异常场景 | 处理方式 |
|---------|---------|
| 处理说明未填写 | 提示"请填写处理说明" |
| 差异已处理 | 提示"该差异已处理" |

---

## 七、数据约束

### 7.1 必填字段

**对账单**
- 支付服务商ID
- 账单日期

**对账差异**
- 对账单ID
- 差异类型
- 服务商订单号

### 7.2 唯一性约束

| 表 | 唯一性约束 |
|----|-----------|
| payment_reconciliation | provider_id + bill_date |

---

## 八、与其他模块的关系

### 8.1 依赖关系

本模块依赖以下模块:

1. **支付渠道管理模块**
   - 引用 payment_provider (对账服务商)

2. **支付交易管理模块**
   - 读取 payment_order (支付流水)

### 8.2 被依赖关系

本模块被以下模块依赖:

1. **支付报表模块**
   - 使用对账数据生成报表

---

## 九、验收标准

### 9.1 功能验收

- [ ] 支持支付流水查询
- [ ] 支持多维度筛选
- [ ] 支持导出Excel
- [ ] 支持下载对账单
- [ ] 支持自动解析对账文件
- [ ] 支持简单匹配对账
- [ ] 支持差异分类展示
- [ ] 支持差异处理标记
- [ ] 对账结果准确

### 9.2 性能验收

- [ ] 流水查询响应时间 ≤ 500ms
- [ ] 导出10000条数据 ≤ 10秒
- [ ] 对账处理时间 ≤ 30秒 (1000笔交易)

### 9.3 数据验收

- [ ] 对账匹配准确率 ≥ 99%
- [ ] 差异类型分类正确
- [ ] 对账结果统计准确

---

## 十、FAQ

### 10.1 对账的意义是什么?

**回答**: 对账用于核对支付中台数据与服务商数据是否一致:
- 发现回调丢失的交易
- 发现数据错误
- 确保资金安全
- 满足财务审计要求

### 10.2 什么时候对账?

**回答**: 建议每日对账:
- 对账日期为前一天
- 时间:每天上午9-10点
- 确保数据完整性

### 10.3 发现差异怎么办?

**回答**: 差异处理流程:
1. 分析差异类型和原因
2. 长款:联系服务商确认,必要时手工补单
3. 短款:核实订单状态,正常情况无需处理
4. 金额差异:核实正确金额,联系服务商调整
5. 标记处理结果

### 10.4 MVP版本为什么只做简单匹配?

**回答**: MVP版本聚焦核心功能:
- 优先满足基础对账需求
- 简单匹配已能发现大部分差异
- 复杂规则匹配和自动调账留待后续版本

### 10.5 对账数据保留多久?

**回答**:
- 对账单记录:永久保留
- 对账文件:保留5年
- 差异记录:永久保留

---

## 变更记录

| 版本 | 日期 | 修改人 | 修改内容 |
|------|------|-------|---------|
| v1.0 | 2026-02-25 | 产品经理 | 初始版本 |
| v1.1 | 2026-02-26 | 产品经理 | 1. 新增payment_reconciliation_diff表的idx_reconcile_type_status复合索引<br>2. 统一订单状态定义(数据库英文,页面中文)<br>3. 新增状态映射说明表<br>4. 新增数据迁移章节<br>5. 更新索引设计表 |
