# 供应商结算管理 — 技术方案

> **依据**：`供应商结算管理功能需求.md`（v1.1）  
> **关联**：`../交易订单管理/交易订单管理技术方案.md`（v1.4）、`交易订单管理功能需求.md`（v1.3）  
> **表与生成逻辑**：`sql/biz_supplier_settlement.sql` 已存在；结算单**仅**在订单 `completePay` 时由 `SettlementOnPayService` 插入

---

## 1. 技术架构

| 项 | 说明 |
| --- | --- |
| **整体** | RuoYi **v3.9.2**（**springboot2** 分支）单体后端 + 若依 **Vue2** 前端 |
| **运行时** | JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
| **数据库** | MySQL **5.7.39**，InnoDB，`utf8mb4` |
| **代码包** | `com.ruoyi.web.modules.trading`（与交易订单同包） |

**本模块职责**

| 能力 | 实现方 | 说明 |
| --- | --- | --- |
| 生成结算单 | 交易订单 `completePay` | `SettlementOnPayService` + `SettlementFeeCalculator` + `SettlementNoGenerator`（**已实现**） |
| 列表 / 详情 / 完成结算 | 本模块 Controller/Service | **待实现** |
| 打印结算凭证 | 前端 | 调详情接口渲染，无独立打印 API |
| 跳转订单详情 | — | **不提供**（需求 v1.1） |

**后端分层**

| 组件 | 职责 |
| --- | --- |
| `BizSupplierSettlementController` | `GET /list`、`GET /{id}`、`PUT /completeSettle` |
| `IBizSupplierSettlementService` / `BizSupplierSettlementServiceImpl` | 查询、完成结算事务 |
| `SettlementValidation`（建议） | 结算凭证校验；完成结算前置条件 |
| `SettlementRules`（建议） | 状态常量、提示语 |
| `BizSupplierSettlementMapper` | 扩充分页列表、`selectById`、`updateCompleteSettle` |
| 复用 | `SettlementOnPayService`、`SettlementFeeCalculator`、`SupplierRules.feeMethodName` |

**业务摘要**

| 场景 | 行为 |
| --- | --- |
| 列表 | `del_flag=0`；`settlementNo`、`orderNo` 模糊 **AND**；`create_time DESC`；JOIN `biz_supplier` 取 `supplierName` |
| 详情 | 主表全字段 + 收费快照 + 凭证 + 状态中文；**无**订单跳转字段/接口 |
| 完成结算 | `@Transactional`：`settlement_status=0` → `1`，写凭证与 `settle_finish_time`；**不回写**订单 |
| 新增/改/删 | **不提供** |

**初始化脚本**：`sql/biz_supplier_settlement.sql`（与订单脚本独立执行即可）

---

## 2. 源码位置

| 类型 | 路径 |
| --- | --- |
| Controller | `.../controller/BizSupplierSettlementController.java` |
| Service | `.../service/IBizSupplierSettlementService.java`、`.../impl/BizSupplierSettlementServiceImpl.java` |
| 校验 | `.../support/SettlementValidation.java`、`SettlementRules.java` |
| 订单侧生成（已有） | `.../support/SettlementOnPayService.java`、`SettlementNoGenerator.java`、`SettlementFeeCalculator.java` |
| Mapper | `.../mapper/BizSupplierSettlementMapper.java` |
| XML | `mapper/trading/BizSupplierSettlementMapper.xml` |
| 实体 | `.../domain/BizSupplierSettlement.java`（需补凭证字段 getter/setter） |
| 测试 | `.../test/.../BizSupplierSettlementServiceImplTest.java`、`BizSupplierSettlementControllerApiTest.java` |

---

## 3. 数据库设计

### 3.1 主表 `biz_supplier_settlement`（已建表）

> 一笔订单一条记录；`uk_order_id` 保证 1:1。金额与费率在**订单完成支付**时写入，本模块**只读**展示，完成结算仅更新状态与凭证。

| 字段名 | 类型 | 非空 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| `id` | `bigint(20)` | Y | 自增 | 主键 |
| `settlement_no` | `varchar(14)` | Y | — | `JSD`+`YYYYMMDD`+3 位序号，**唯一** |
| `order_id` | `bigint(20)` | Y | — | `biz_trade_order.id`，**唯一** |
| `order_no` | `varchar(11)` | Y | — | 冗余，列表按关联订单号模糊 |
| `supplier_id` | `bigint(20)` | Y | — | 冗余 |
| `total_heads` | `int(11)` | Y | — | 来自订单 |
| `total_amount` | `decimal(12,2)` | Y | — | 来自订单（元） |
| `fee_method` | `tinyint(4)` | Y | — | 快照：`1` 按户 `2` 按头 `3` 按额 |
| `fee_standard` | `decimal(12,2)` | N | NULL | 快照：元/头 |
| `transaction_fee_rate` | `decimal(5,2)` | N | NULL | 快照：交易费率 % |
| `management_fee_rate` | `decimal(5,2)` | N | NULL | 快照：管理费率 % |
| `service_fee_amount` | `decimal(12,2)` | Y | — | 服务费（生成时计算固化） |
| `payable_amount` | `decimal(12,2)` | Y | — | 实际应付 = 总金额 − 服务费 |
| `settlement_status` | `char(1)` | Y | `'0'` | `0` 待结算 `1` 已完成 |
| `settle_voucher_url` | `varchar(512)` | N | NULL | 完成结算时写入 |
| `settle_voucher_path` | `varchar(512)` | N | NULL | 完成结算时写入 |
| `settle_finish_time` | `datetime` | N | NULL | 结算完成时间 |
| `del_flag` | `char(1)` | Y | `'0'` | `0` 存在 `2` 逻辑删除 |
| `create_by` / `create_time` / `update_by` / `update_time` | 若依惯例 | — | — | **结算创建时间** = `create_time` |
| `remark` | `varchar(500)` | N | NULL | 备注 |

**索引**：`PRIMARY KEY (id)`；`UNIQUE uk_settlement_no`；`UNIQUE uk_order_id`；`KEY idx_order_no`；`KEY idx_supplier`；`KEY idx_settlement_status`；`KEY idx_create_time`；`KEY idx_del_flag`。

**DDL**：`sql/biz_supplier_settlement.sql`（无需新增表）。

### 3.2 关联表（只读）

| 表 | 用途 |
| --- | --- |
| `biz_trade_order` | 完成结算前校验：订单 `order_status=1`、`del_flag=0` |
| `biz_supplier` | 列表/详情 `supplier_name` |

### 3.3 枚举

| 字段 | 值 | 含义 |
| --- | --- | --- |
| `settlement_status` | `0` / `1` | 待结算 / 已完成 |
| `del_flag` | `0` / `2` | 正常 / 已删 |
| `fee_method` | `1` / `2` / `3` | 按户 / 按头 / 按额（与 `biz_supplier` 一致） |

### 3.4 与订单表关系

```text
biz_trade_order (1) ──uk_order_id──► biz_supplier_settlement (1)
```

- 订单 `order_status=0`：无结算行。  
- 订单 `completePay` 成功：插入一行 `settlement_status=0`。  
- 本模块 `completeSettle` 成功：`settlement_status=1`；订单仍为 `order_status=1`。

---

## 4. 字段命名（JSON 小驼峰）

| JSON | 库表 | 说明 |
| --- | --- | --- |
| `id` | `id` | 主键 |
| `settlementNo` | `settlement_no` | 结算单编号 |
| `orderId` | `order_id` | 关联订单 ID（详情展示，**不用于跳转**） |
| `orderNo` | `order_no` | 关联订单编号；列表筛选项 |
| `supplierId` | `supplier_id` | |
| `supplierName` | — | JOIN `biz_supplier` |
| `totalHeads` | `total_heads` | |
| `totalAmount` | `total_amount` | |
| `feeMethod` | `fee_method` | `1`/`2`/`3` |
| `feeMethodName` | — | `SupplierRules.feeMethodName` |
| `feeStandard` | `fee_standard` | 按头快照 |
| `transactionFeeRate` | `transaction_fee_rate` | 按额快照 % |
| `managementFeeRate` | `management_fee_rate` | 按额快照 % |
| `serviceFeeAmount` | `service_fee_amount` | |
| `payableAmount` | `payable_amount` | |
| `settlementStatus` | `settlement_status` | `0`/`1` |
| `settlementStatusName` | — | 待结算 / 已完成 |
| `settleVoucherUrl` / `settleVoucherPath` | 结算凭证 | 完成结算入参；已完成可预览 |
| `createTime` | `create_time` | 结算创建时间 |
| `settleFinishTime` | `settle_finish_time` | 结算完成时间 |
| `settlementNo`（筛） | `settlement_no` | 列表模糊 `LIKE` |
| `orderNo`（筛） | `order_no` | 列表模糊 `LIKE` |

---

## 5. 核心业务实现

### 5.1 结算单生成（订单模块，已实现）

触发：`PUT /tradeMarket/tradeOrder/completePay` 事务内调用 `SettlementOnPayService.createFromOrder`。

| 步骤 | 说明 |
| --- | --- |
| 幂等 | `selectByOrderId` 已存在 → 抛错，订单保持待支付 |
| 编号 | `SettlementNoGenerator`：`JSD`+日期+3 位；当日超 999 与订单编号策略一致抛错 |
| 费用 | `SettlementFeeCalculator`：`HALF_UP` 2 位小数；快照 `fee_*` 与 `service_fee_amount`、`payable_amount` |
| 初始状态 | `settlement_status=0`；凭证、完成时间为空 |

公式（与功能需求 §3.5 一致）：

```text
fee_method=1 → serviceFee = 0
fee_method=2 → serviceFee = totalHeads × feeStandard
fee_method=3 → serviceFee = totalAmount × (transactionFeeRate + managementFeeRate) / 100
payableAmount = totalAmount − serviceFee
```

### 5.2 完成结算 `completeSettle`（本模块）

**接口**：`PUT /tradeMarket/supplierSettlement/completeSettle`

**事务步骤**（全部成功或回滚）：

1. `SettlementValidation.validateSettleVoucher`：`id`、`settleVoucherUrl`、`settleVoucherPath` 非空；后缀 `jpg|jpeg|png`（与 `TradeOrderValidation.validatePayVoucher` 规则一致；大小 ≤10MB 由 `/common/upload` 保证）。  
2. `selectBizSupplierSettlementById`：`del_flag=0`；`settlement_status=0`；否则「仅待结算状态可完成结算」。  
3. `biz_trade_order`：`order_id` 对应订单 `order_status=1` 且 `del_flag=0`；否则业务异常。  
4. `UPDATE biz_supplier_settlement SET settlement_status='1', settle_voucher_url=?, settle_voucher_path=?, settle_finish_time=now(), update_by=?, update_time=now() WHERE id=? AND settlement_status='0' AND del_flag='0'`；`updated=0` → 已完成或并发冲突提示。  
5. **不** `UPDATE` 订单表。

**幂等**：已完成不展示「完成结算」；接口层对 `settlement_status=1` 直接拒绝。

### 5.3 列表 / 详情

- 列表 SQL：`FROM biz_supplier_settlement s LEFT JOIN biz_supplier sup ON s.supplier_id = sup.id AND sup.del_flag='0' WHERE s.del_flag='0'`。  
- 详情：在列表字段基础上返回收费快照明细（`feeMethod` + 对应费率字段）；**不**组装订单 `lineList`、支付凭证。  
- 排序：`s.create_time DESC, s.id DESC`。  
- 默认分页：`pageSize=20`。

### 5.4 实体与 Mapper 补齐（实现时注意）

当前 `BizSupplierSettlement` / `BizSupplierSettlementMapper.xml` 仅支持 `insert`、`selectByOrderId`、编号序号查询。实现本模块前需：

- 实体增加 `settleVoucherUrl`、`settleVoucherPath`；`resultMap` 映射 `settle_finish_time` 及凭证列。  
- 新增 `selectBizSupplierSettlementList`、`selectBizSupplierSettlementById`、`updateCompleteSettle`。

---

## 6. 接口设计

**Base Path**：`/tradeMarket/supplierSettlement`  
**权限**：`tradeMarket:supplierSettlement:list|query|settle`  
**响应**：`AjaxResult` / `TableDataInfo`（`code`、`msg`、`rows`/`data`）

| 说明 | HTTP | URI | 权限 |
| --- | --- | --- | --- |
| 分页列表 | GET | `/list` | `list` |
| 详情 | GET | `/{id}` | `query` |
| 完成结算 | PUT | `/completeSettle` | `settle` |

> 本期**无** `POST`/`DELETE`/`PUT /` 全量修改。打印凭证由前端根据详情数据生成，**无** `/print` 接口。

### 6.1 列表 `GET /list`

| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `pageNum` | int | N | 默认 `1` |
| `pageSize` | int | N | 默认 `20` |
| `settlementNo` | string | N | 结算单编号模糊 |
| `orderNo` | string | N | 关联订单编号模糊 |

- 条件：`del_flag=0`；两筛选项同时传则 **AND**。  
- 行字段：功能需求 §5.2 所列（小驼峰见 §4）。  
- `settlementStatus=0`：操作区「完成结算」「查看」；`1`：「打印凭证」「查看」（前端按权限显隐）。

### 6.2 详情 `GET /{id}`

- `data`：`BizSupplierSettlement` 全量展示字段 + `supplierName` + `feeMethodName` + `settlementStatusName`。  
- **不返回**订单跳转 URL；**不嵌套**订单明细 `lineList`。

### 6.3 完成结算 `PUT /completeSettle`

| Body | 必填 | 说明 |
| --- | --- | --- |
| `id` | Y | 结算单主键 |
| `settleVoucherUrl` | Y | 先 `POST /common/upload` |
| `settleVoucherPath` | Y | 上传返回路径 |

- 成功：`code=200`；`settlementStatus=1`；`settleFinishTime` 有值。  
- 失败：保持 `settlement_status=0`；`msg` 示例见功能需求 §12。

### 6.4 前端联调（共享）

| 用途 | 接口 |
| --- | --- |
| 结算凭证上传 | `POST /common/upload` |
| 查订单（用户自行） | `GET /tradeMarket/tradeOrder/list?orderNo=…`（**非**本模块跳转） |

---

## 7. 关联方案：交易订单管理

### 7.1 职责边界

| 能力 | 交易订单 | 供应商结算（本模块） |
| --- | --- | --- |
| 写 `biz_supplier_settlement` | `completePay` 插入 | — |
| 读 / 完成结算 | — | `list` / `{id}` / `completeSettle` |
| 支付凭证 | 订单表 | — |
| 结算凭证 | — | 结算表 |
| 平台业务终点 | 订单已完成 | **结算已完成**（需求 v1.1） |
| 跨模块跳转 | — | **禁止**跳转订单详情 |

### 7.2 端到端时序

```mermaid
sequenceDiagram
    participant O as tradeOrder
    participant S as supplierSettlement
    O->>O: completePay(支付凭证)
    O->>S: insert 待结算+费用快照
    S->>S: completeSettle(结算凭证)
    Note over S: 不回写订单；流程结束
```

### 7.3 状态对照

```text
订单 order_status:     0 待支付 ──completePay──► 1 已完成
结算 settlement_status: (无) ──生成──► 0 待结算 ──completeSettle──► 1 已完成 [平台终点]
```

### 7.4 异常协同（实现校验要点）

| 场景 | 处理 |
| --- | --- |
| 订单支付失败 | 无结算行 |
| 订单支付成功 | 必有 1 条 `settlement_status=0` |
| 结算完成失败 | 保持待结算，可重试 |
| 结算已完成 | 拒绝 `completeSettle`；订单仍已完成 |
| 订单已逻辑删除 | 不应存在结算；若存在则完成结算校验失败 |

### 7.5 与订单技术方案交叉引用

| 订单方案章节 | 本模块对应 |
| --- | --- |
| §3.3 `biz_supplier_settlement` | §3.1 同表 |
| §5.4 `completePay` | §5.1 生成逻辑 |
| §7.2 结算接口建议 | §6 定稿接口 |
| §7.3 状态一致性 | §7.3 |

---

## 8. 菜单与权限（示例）

| 类型 | 名称 | 权限标识 |
| --- | --- | --- |
| 菜单 | 供应商结算管理 | `tradeMarket:supplierSettlement:list` |
| 按钮 | 查询 | `tradeMarket:supplierSettlement:query` |
| 按钮 | 完成结算 | `tradeMarket:supplierSettlement:settle` |

组件路径建议：`tradeMarket/supplierSettlement/index`（与 `tradeOrder/index` 并列，**无**路由参数跳转订单）。

---

## 9. 交付清单

- [x] `sql/biz_supplier_settlement.sql`
- [x] `SettlementOnPayService`、`SettlementFeeCalculator`、`SettlementNoGenerator`
- [x] `BizSupplierSettlement` 凭证字段 + Mapper 列表/详情/完成结算
- [x] `BizSupplierSettlementController`、`IBizSupplierSettlementService` 实现
- [x] `SettlementValidation` / `SettlementRules`
- [ ] 菜单 SQL / 权限配置
- [x] 单元测试 + MockMvc（`SettlementValidationTest`、`BizSupplierSettlementServiceImplTest`、`BizSupplierSettlementControllerApiTest`）

---

## 10. 修订记录

| 版本 | 说明 |
| --- | --- |
| 1.0 | 初稿：对齐功能需求 v1.1；复用已有表与订单侧生成逻辑；列表/详情/完成结算接口；与交易订单关联方案 |
