补充供应商余额与支付类型接口说明(#6834)
changelog-filename-gate / validate (push) Successful in 2s

这个提交包含在:
lc
2026-08-31 12:24:30 +08:00
父节点 2b60fc3323
当前提交 430d825904
@@ -0,0 +1,488 @@
---
schema: "hl-changelog/v2"
ticket: "6834"
title: "供应商余额支付类型与草稿编辑项"
consumer: "admin"
author: "lc(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "pending"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: "2026-08-31"
status_note: "PR #6860 已合并 dev-v3,合并提交 6ed8e24c0f04051c9c4385c79de67f255abb4952 已部署 TEST。真实 Gateway 已验证支付类型字典、新增必填与失败零写入、余额和支付类型保存回显、草稿省略 changeReason 更新及验收数据清理。当前状态:后端已就绪,前端待处理。"
updated_at: "2026-08-31"
base: "dev-v3"
---
# 供应商余额支付类型与草稿编辑项
供应商新增、提交、编辑和详情增加 `balance`、`paymentType`。新增与提交时两项必填;编辑时可按增量提交,详情用于回显。支付类型从 `supplier_payment_type` 字典读取。
供应商详情 `status=DRAFT` 时,编辑页隐藏“变更原因”;其他状态继续显示并必填。
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---:|---|---|---|---|---|
| 1 | 新增供应商草稿 | POST | `/admin/supplier/items/add` | 请求字段 | `balance`、`paymentType` 必填 |
| 2 | 提交供应商审批 | POST | `/admin/supplier/items/{supplierId}/submit` | 请求字段 | 完整表单中的两个字段必填 |
| 3 | 编辑供应商 | PUT | `/admin/supplier/items/{supplierId}/update` | 请求字段与状态规则 | 可更新两个字段;草稿可省略 `changeReason` |
| 4 | 查询供应商基本信息 | GET | `/admin/supplier/items/{supplierId}/basic-info/view` | 响应字段 | 返回 `balance`、`paymentType`、`status` |
| 5 | 查询支付类型字典类型 | GET | `/admin/dict/type` | 新增字典数据 | 可按 `supplier_payment_type` 查询字典类型 |
| 6 | 查询支付类型字典项 | GET | `/admin/dict/data/supplier_payment_type` | 新增字典数据 | 返回现付、签单、月付 |
## 三、接口详情
### 1. 新增供应商草稿 `POST /admin/supplier/items/add`
**VO**: `SupplierDraftSaveReqVO / SupplierWriteRespVO`
#### 使用场景
新增供应商时录入初始余额并选择支付类型。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---:|---|---|
| `balance` | Body | Number | 是 | 最多 16 位整数、2 位小数,可为正数、0 或负数 | 供应商当前余额 |
| `paymentType` | Body | String | 是 | 必须命中当前生效的 `supplier_payment_type` 字典项 | 支付类型值,传 `1`、`2` 或 `3` |
| `fullName` / `taxNo` / `mainCooperation` | Body | String | 是 | 沿用既有规则 | 其他新增必填字段 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data.supplierId` | String | 新供应商 ID |
| `data.status` | String | 新增草稿为 `DRAFT` |
| `data.updateTime` | String | 后续编辑使用的并发版本 |
#### 请求示例
```json
{
"fullName": "示例供应商有限公司",
"taxNo": "91350211M000100Y46",
"mainCooperation": "旅游资源合作",
"balance": 1200.50,
"paymentType": "1"
}
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"supplierId": "2094278854020399106",
"status": "DRAFT",
"updateTime": "2026-08-31 12:19:23"
}
}
```
#### 空数据 / 降级响应
`balance` 或 `paymentType` 省略、为 `null` 或支付类型为空白时返回业务码 `400`,不创建草稿。
#### 错误响应
```json
{"code":400,"message":"余额不能为空","success":false,"data":null}
```
```json
{"code":400,"message":"供应商支付类型不合法或已停用","success":false,"data":null}
```
#### 业务边界
- 前端必须传数值型 `balance`,不要传格式化金额字符串。
- `paymentType` 传字典 `dictValue`,不要传“现付”等展示文本。
- 校验失败时不产生供应商记录。
### 2. 提交供应商审批 `POST /admin/supplier/items/{supplierId}/submit`
**VO**: `SupplierSubmitReqVO / SupplierApprovalCommandRespVO`
#### 使用场景
把完整供应商表单提交审批时,一并提交余额和支付类型。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---:|---|---|
| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 草稿供应商 |
| `balance` | Body | Number | 是 | 最多 16 位整数、2 位小数 | 当前余额 |
| `paymentType` | Body | String | 是 | 当前生效字典值 | 支付类型 |
| `expectedUpdateTime` | Body | String | 是 | `yyyy-MM-dd HH:mm:ss` | 当前供应商并发版本 |
| 其他完整表单字段 | Body | 对应类型 | 按既有规则 | 沿用现有提交契约 | 不得只提交本次新增字段 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data.approvalLogId` | String | 审批记录 ID |
| `data.approvalStatus` | String | 审批状态 |
#### 请求示例
```json
{
"fullName": "示例供应商有限公司",
"taxNo": "91350211M000100Y46",
"mainCooperation": "旅游资源合作",
"balance": 1200.50,
"paymentType": "1",
"expectedUpdateTime": "2026-08-31 12:19:23"
}
```
#### 响应示例
```json
{"code":200,"message":"成功","success":true,"data":{"approvalLogId":"2094279000000000001","approvalStatus":"PENDING"}}
```
#### 空数据 / 降级响应
两个新增字段任一为空即拒绝提交,审批状态不推进。
#### 错误响应
```json
{"code":400,"message":"支付类型不能为空","success":false,"data":null}
```
#### 业务边界
- 提交仍是完整表单命令,并继续执行既有状态、并发、审批和幂等门禁。
- 支付类型失效或不存在时失败关闭,不使用本地默认值代替。
### 3. 编辑供应商 `PUT /admin/supplier/items/{supplierId}/update`
**VO**: `SupplierUpdateReqVO / SupplierWriteRespVO`
#### 使用场景
编辑页修改余额或支付类型;根据详情的服务端状态决定是否显示变更原因。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---:|---|---|
| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 |
| `balance` | Body | Number | 否 | 最多 16 位整数、2 位小数 | 省略表示不修改 |
| `paymentType` | Body | String | 否 | 非空时必须命中当前生效字典项 | 省略表示不修改 |
| `changeReason` | Body | String | 条件必填 | 最长 500 | `DRAFT` 可省略;其他状态去空白后必须非空 |
| `expectedUpdateTime` | Body | String | 是 | `yyyy-MM-dd HH:mm:ss` | 详情最新并发版本 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data.supplierId` | String | 供应商 ID |
| `data.status` | String | 保存后的服务端状态 |
| `data.updateTime` | String | 保存后的新并发版本 |
#### 请求示例
`DRAFT` 草稿完全省略 `changeReason`:
```json
{
"balance": -12.34,
"paymentType": "3",
"expectedUpdateTime": "2026-08-31 12:19:23"
}
```
#### 响应示例
```json
{"code":200,"message":"成功","success":true,"data":{"supplierId":"2094278854020399106","status":"DRAFT","updateTime":"2026-08-31 12:19:33"}}
```
#### 空数据 / 降级响应
省略 `balance` 或 `paymentType` 表示该字段不修改;历史供应商尚未补录时,详情可返回 `null`。
#### 错误响应
非草稿缺少变更原因:
```json
{"code":400,"message":"变更原因不能为空","success":false,"data":null}
```
#### 业务边界
- 是否为草稿只取服务端锁定后的当前状态,不接收客户端自报状态。
- 草稿隐藏“变更原因”并省略 `changeReason`;非草稿继续显示且必填。
- 更新成功后使用新 `updateTime` 重新查询详情;并发失败返回既有 `395014`。
### 4. 查询供应商基本信息 `GET /admin/supplier/items/{supplierId}/basic-info/view`
**VO**: `SupplierBasicInfoRespVO`
#### 使用场景
新增后或进入编辑页时回显余额、支付类型和当前状态。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---:|---|---|
| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data.balance` | Number/null | 当前余额;历史未补录可为 `null` |
| `data.paymentType` | String/null | `supplier_payment_type` 字典值;历史未补录可为 `null` |
| `data.status` | String | 用于控制变更原因框 |
| `data.updateTime` | String | 编辑请求的并发版本 |
#### 请求示例
```http
GET /admin/supplier/items/2094278854020399106/basic-info/view
Authorization: Bearer <admin-token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"supplierId": "2094278854020399106",
"balance": -12.34,
"paymentType": "3",
"status": "DRAFT",
"updateTime": "2026-08-31 12:19:33"
}
}
```
#### 空数据 / 降级响应
历史供应商没有新字段时返回 `null`;前端显示未补录,不自行写入默认值。
#### 错误响应
```json
{"code":395001,"message":"供应商不存在","success":false,"data":null}
```
#### 业务边界
- `paymentType` 原样返回字典值,中文标签由字典项映射。
- 业务失败可能仍是 HTTP 200,必须同时判断 `code` 和 `success`。
### 5. 查询支付类型字典类型 `GET /admin/dict/type`
**VO**: `PageResult<SysDictTypeRespVO>`
#### 使用场景
字典管理页或联调时确认 `supplier_payment_type` 类型已经存在。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---:|---|---|
| `page` | Query | Number | 否 | 默认 1 | 页码 |
| `pageSize` | Query | Number | 否 | 默认 20 | 每页条数 |
| `keyword` | Query | String | 否 | 传 `supplier_payment_type` | 按编码或名称搜索 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data.records[].dictType` | String | `supplier_payment_type` |
| `data.records[].dictName` | String | `供应商支付类型` |
| `data.records[].status` | String | `ACTIVE` |
#### 请求示例
```http
GET /admin/dict/type?page=1&pageSize=20&keyword=supplier_payment_type
```
#### 响应示例
```json
{"code":200,"message":"成功","success":true,"data":{"records":[{"dictType":"supplier_payment_type","dictName":"供应商支付类型","status":"ACTIVE"}],"total":1,"page":1,"pageSize":20}}
```
#### 空数据 / 降级响应
未命中时 `records=[]`;这表示字典未就绪,前端不要回退到其他结算字典。
#### 错误响应
```json
{"code":401,"message":"Token无效或已过期","success":false,"data":null}
```
#### 业务边界
- 该接口只查询字典类型,不直接提供下拉项。
- 下拉选项必须继续调用下一接口。
### 6. 查询支付类型字典项 `GET /admin/dict/data/supplier_payment_type`
**VO**: `List<SysDictDataRespVO>`
#### 使用场景
新增、编辑供应商页面加载支付类型下拉选项。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---:|---|---|
| 无 | - | - | 否 | 字典编码固定在路径中 | 无请求体、查询参数或动态路径参数 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| `data[].dictValue` | String | 请求保存的值 |
| `data[].dictLabel` | String | 下拉展示文案 |
| `data[].sortOrder` | Number | 排序号 |
| `data[].status` | String | 当前均为 `ACTIVE` |
#### 请求示例
```http
GET /admin/dict/data/supplier_payment_type
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"success": true,
"data": [
{"dictValue":"1","dictLabel":"现付","sortOrder":10,"status":"ACTIVE"},
{"dictValue":"2","dictLabel":"签单","sortOrder":20,"status":"ACTIVE"},
{"dictValue":"3","dictLabel":"月付","sortOrder":30,"status":"ACTIVE"}
]
}
```
#### 空数据 / 降级响应
返回空数组或调用失败时禁用提交并提示字典加载失败,不硬编码替代值。
#### 错误响应
```json
{"code":401,"message":"Token无效或已过期","success":false,"data":null}
```
#### 业务边界
- 请求保存 `dictValue`,界面展示 `dictLabel`。
- 后端每次写入都动态校验当前生效项;已停用或未知值返回业务码 `400`。
## 四、契约约束与正确调用方式
1. 页面初始化先查询详情与支付类型字典项,用 `paymentType` 匹配 `dictValue`。
2. 新增和提交时 `balance`、`paymentType` 都必填;编辑时只发送实际修改字段和最新 `expectedUpdateTime`。
3. `status=DRAFT` 隐藏“变更原因”并可省略 `changeReason`;其他状态必须收集非空原因。
4. 金额输入保留最多两位小数,允许负数;不要把千分位格式化文本发给后端。
| 场景 | payload | 结果 |
|---|---|---|
| 新增完整 | `{ "balance": 100.00, "paymentType": "1", ... }` | 成功 |
| 新增缺余额 | `{ "paymentType": "1", ... }` | `400`,余额不能为空 |
| 新增非法支付类型 | `{ "balance": 100.00, "paymentType": "9", ... }` | `400`,支付类型不合法或已停用 |
| 草稿编辑 | `{ "balance": -12.34, "paymentType": "3", "expectedUpdateTime": "..." }` | 成功,可省略 `changeReason` |
| 非草稿编辑缺原因 | `{ "balance": 0, "expectedUpdateTime": "..." }` | `400`,变更原因不能为空 |
## 五、数据库行为
- 新增或更新成功后,详情回读相同的 `balance`、`paymentType`。
- 历史供应商不强制回填,新字段可返回 `null`;创建和提交的新数据仍由接口强制必填。
- 审批与非草稿变更继续保留两个字段的业务快照;失败时不产生部分写入。
## 六、边界行为
- `balance` 最多 16 位整数和 2 位小数,正数、0、负数均有效。
- `paymentType` 必须是当前生效字典值;未知、空白或停用值不保存。
- 未登录返回业务码 `401`;不存在返回 `395001`;并发版本过期返回 `395014`。
- 不新增权限、Gateway 路由、Redis、MQ 或配置行为。
## 六.5、枚举 / 数据字典
### `paymentType`(字典 `supplier_payment_type`)
**所属字段**: `SupplierDraftSaveReqVO.paymentType / SupplierUpdateReqVO.paymentType / SupplierBasicInfoRespVO.paymentType` | **类型**: `String`
| 值 | 中文 | 说明 |
|---|---|---|
| `1` | 现付 | 按现付方式处理 |
| `2` | 签单 | 按签单方式处理 |
| `3` | 月付 | 按月付方式处理 |
## 六.6、修改前后对比
| 项目 | 修改前 | 修改后 |
|---|---|---|
| 新增与提交 | 无余额、支付类型字段 | 两字段必填并校验 |
| 编辑与详情 | 无法录入和回显两字段 | 支持增量修改并原值回显 |
| 支付类型选项 | 无专用字典 | 使用 `supplier_payment_type` 三个生效项 |
| 草稿变更原因 | 页面仍可能显示 | `DRAFT` 隐藏;非草稿继续必填 |
## 六.7、影响评估
- **是否破坏向后兼容**:新增、提交请求增加必填字段,前端必须同步;编辑与详情为兼容扩展。
- **前端是否必须同步上线**:是,需要新增两个控件、接入字典并按状态调整变更原因框。
- **前端 workaround 清理点**:删除支付类型硬编码和草稿 `changeReason` 必填/展示逻辑;非草稿校验必须保留。
## 七、不影响范围
- 不修改供应商权限、状态机、审批流程、并发、软删除和既有错误码。
- 不复用 `resource_settle_type`,也不影响供应商账户、合同和资源关系接口。
- 本次仅交付后端接口 Changelog,不修改任何前端源码或资源。
## 八、测试环境已验证
- TEST Gateway 查询到字典类型及精确字典项 `1-现付`、`2-签单`、`3-月付`。
- 缺余额、缺支付类型、非法支付类型均返回 `400`,验证前后列表为空。
- 有效新增返回 `DRAFT`;详情回显 `balance=12.34`、`paymentType=1`。
- 草稿省略 `changeReason` 更新成功;详情回显 `balance=-12.34`、`paymentType=3`。
- 验收草稿已通过删除接口清理,列表为空且详情返回“供应商不存在”。
## 当前状态
- 后端:已部署并已验证。
- 前端:待处理。
## 十、相关文档
- Issue:[#6834](https://git.1814.love:8443/wx/HL/issues/6834)
- 后端 PR:[#6860](https://git.1814.love:8443/wx/HL/pulls/6860)
- 合并提交:[6ed8e24c](https://git.1814.love:8443/wx/HL/commit/6ed8e24c0f04051c9c4385c79de67f255abb4952)
## 关联 / 联系人
- **Issue**: [#6834](https://git.1814.love:8443/wx/HL/issues/6834)
- **PR**: [#6860](https://git.1814.love:8443/wx/HL/pulls/6860)
- **后端负责人**: @lc
- **当前状态**: 后端已就绪,前端待处理。