Merge pull request 'docs(changelog): 补充草稿结算编辑契约 #6669' (#82) from chore/6669-6676-supplier-draft-settlement-changelog into main
changelog-filename-gate / validate (push) Successful in 2s
changelog-filename-gate / validate (push) Successful in 2s
此提交已合并在合并请求 #82 中。
这个提交包含在:
@@ -0,0 +1,359 @@
|
|||||||
|
---
|
||||||
|
schema: "hl-changelog/v2"
|
||||||
|
ticket: "6669"
|
||||||
|
title: "供应商草稿结算信息编辑与可选字段清空"
|
||||||
|
consumer: "admin"
|
||||||
|
author: "lc(GIT)"
|
||||||
|
change_type: "修改接口"
|
||||||
|
backend_status: "deployed"
|
||||||
|
gateway_status: "verified"
|
||||||
|
frontend_status: "pending"
|
||||||
|
frontend_owner: "mmg"
|
||||||
|
frontend_ref: ""
|
||||||
|
target_release: "v2.1"
|
||||||
|
verified_at: "2026-08-29"
|
||||||
|
status_note: "#6669 与补充工单 #6676 已合并 dev-v3;最终提交 af5ea05df3d7490c97e6f4329c145a4014396bee 已由 Deploy Panel 任务 9be3a694 部署 TEST。真实 Gateway 已验证草稿结算创建、回读、修改、六个可选字段清空、整项清空、并发失败零写入和数据清理。当前状态:待前端处理。"
|
||||||
|
updated_at: "2026-08-29"
|
||||||
|
base: "dev-v3"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 供应商草稿结算信息编辑与可选字段清空
|
||||||
|
|
||||||
|
供应商编辑接口新增 `initialAccounts` 完整快照。新建时登记的初始结算信息现在可在草稿编辑页读回、修改或清空;`changeReason` 和 `expectedUpdateTime` 继续必填。
|
||||||
|
|
||||||
|
## 二、变更接口清单
|
||||||
|
|
||||||
|
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||||
|
|---:|---|---|---|---|---|
|
||||||
|
| 1 | 编辑供应商 | PUT | `/admin/supplier/items/{supplierId}/update` | 修改请求与响应 | 新增可选 `initialAccounts` 完整快照,仅草稿态可维护 |
|
||||||
|
| 2 | 查询供应商账户列表 | GET | `/admin/supplier/items/{supplierId}/account-info/list` | 修改响应语义 | 草稿供应商可读回其 `DRAFT` 初始账户 |
|
||||||
|
| 3 | 查询收款账户详情 | GET | `/admin/supplier/bank-accounts/{accountId}/view` | 修改响应语义 | 所属供应商为草稿时可读回 `DRAFT` 账户详情 |
|
||||||
|
|
||||||
|
## 三、接口详情
|
||||||
|
|
||||||
|
### 1. 编辑供应商 `PUT /admin/supplier/items/{supplierId}/update`
|
||||||
|
|
||||||
|
**VO**: `SupplierUpdateReqVO / SupplierWriteRespVO`
|
||||||
|
|
||||||
|
#### 使用场景
|
||||||
|
|
||||||
|
在供应商草稿编辑页维护与新建供应商相同的一项初始结算信息。省略 `initialAccounts` 不修改结算信息,空数组清空,1 项执行完整替换。
|
||||||
|
|
||||||
|
#### 入参
|
||||||
|
|
||||||
|
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||||
|
|---|---|---|---:|---|---|
|
||||||
|
| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 |
|
||||||
|
| `initialAccounts` | Body | Array | 否 | 最多 1 项 | 省略不修改;`[]` 清空;1 项完整替换 |
|
||||||
|
| `initialAccounts[].accountType` | Body | String | 项内是 | `CORPORATE` / `PERSONAL` | 账户类型 |
|
||||||
|
| `initialAccounts[].bankName` | Body | String | 项内是 | 最长 500 字符 | 开户银行 |
|
||||||
|
| `initialAccounts[].accountNo` | Body | String | 项内是 | 规范化后 8 至 32 位数字 | 收款账号 |
|
||||||
|
| `initialAccounts[].bankBranch` | Body | String/null | 否 | 最长 500 字符 | 省略或 `null` 可清空 |
|
||||||
|
| `initialAccounts[].proofFileUrls` | Body | Array/null | 否 | 最多 20 项 HTTPS 地址 | 省略、`null` 或 `[]` 可清空 |
|
||||||
|
| `initialAccounts[].settleMode` | Body | String/null | 否 | `PREPAY` / `MONTHLY` / `SINGLE` | 可清空 |
|
||||||
|
| `initialAccounts[].accountPeriod` | Body | String/null | 否 | 最长 50 字符 | 仅月结时填写,可清空 |
|
||||||
|
| `initialAccounts[].invoiceType` | Body | String/null | 否 | `SPECIAL` / `NORMAL` / `NONE` | 可清空 |
|
||||||
|
| `initialAccounts[].taxRate` | Body | String/null | 否 | 0% 至 100%,最多两位小数 | 可清空 |
|
||||||
|
| `changeReason` | Body | String | 是 | 去空白后非空,最长 500 字符 | 审计原因,继续必填 |
|
||||||
|
| `expectedUpdateTime` | Body | String | 是 | `yyyy-MM-dd HH:mm:ss` | 供应商主体并发版本,继续必填 |
|
||||||
|
|
||||||
|
#### 出参
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `data.supplierId` | String | 供应商雪花 ID |
|
||||||
|
| `data.status` | String | 当前为 `DRAFT` |
|
||||||
|
| `data.initialAccounts` | Array | 保存后的 0 或 1 项账户摘要 |
|
||||||
|
| `data.updateTime` | String | 新的供应商并发版本 |
|
||||||
|
|
||||||
|
雪花 ID 均按字符串处理。
|
||||||
|
|
||||||
|
#### 请求示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"changeReason": "维护草稿结算信息",
|
||||||
|
"expectedUpdateTime": "2026-08-29 17:01:00",
|
||||||
|
"initialAccounts": [
|
||||||
|
{
|
||||||
|
"accountType": "PERSONAL",
|
||||||
|
"bankName": "示例银行",
|
||||||
|
"accountNo": "6222000012345678"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"supplierId": "2094000000000000000",
|
||||||
|
"status": "DRAFT",
|
||||||
|
"initialAccounts": [
|
||||||
|
{
|
||||||
|
"accountId": "2094000000000000001",
|
||||||
|
"accountType": "PERSONAL",
|
||||||
|
"bankName": "示例银行",
|
||||||
|
"bankBranch": null,
|
||||||
|
"accountNo": "6222000012345678",
|
||||||
|
"settleMode": null,
|
||||||
|
"accountPeriod": null,
|
||||||
|
"invoiceType": null,
|
||||||
|
"taxRate": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updateTime": "2026-08-29 17:01:01"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 空数据 / 降级响应
|
||||||
|
|
||||||
|
- 省略 `initialAccounts`:不修改现有初始账户。
|
||||||
|
- 传 `initialAccounts: []`:软删除草稿初始账户,写响应返回空数组。
|
||||||
|
- 1 项中省略 6 个可选字段:`bankBranch`、`proofFileUrls`、`settleMode`、`accountPeriod`、`invoiceType`、`taxRate` 均清空;附件在读取响应中表现为空数组。
|
||||||
|
|
||||||
|
#### 错误响应
|
||||||
|
|
||||||
|
缺少审计或并发字段时失败且账户零写入:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "code": 400, "message": "变更原因不能为空", "success": false, "data": null }
|
||||||
|
```
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "code": 400, "message": "expectedUpdateTime不能为空", "success": false, "data": null }
|
||||||
|
```
|
||||||
|
|
||||||
|
过期版本继续返回既有并发错误:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "code": 395014, "message": "数据已被他人修改,请刷新后重试", "success": false, "data": null }
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 业务边界
|
||||||
|
|
||||||
|
- `initialAccounts` 仅允许供应商为 `DRAFT` 时维护;否则返回既有状态错误 `395005`,账户零写入。
|
||||||
|
- 同账号完整替换保留原 `accountId`;账号全局唯一、事务、行锁、幂等和账户审计保持不变。
|
||||||
|
- 生效后的账户继续走独立新增与审批接口,供应商编辑不得绕过账户状态机。
|
||||||
|
|
||||||
|
### 2. 查询供应商账户列表 `GET /admin/supplier/items/{supplierId}/account-info/list`
|
||||||
|
|
||||||
|
**VO**: `SupplierAccountInfoRespVO / SupplierBankAccountRespVO`
|
||||||
|
|
||||||
|
#### 使用场景
|
||||||
|
|
||||||
|
进入供应商编辑页时加载“结算信息”table。供应商为草稿时,列表包含其初始 `DRAFT` 账户。
|
||||||
|
|
||||||
|
#### 入参
|
||||||
|
|
||||||
|
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||||
|
|---|---|---|---:|---|---|
|
||||||
|
| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 |
|
||||||
|
|
||||||
|
无 Query 参数,无请求体。
|
||||||
|
|
||||||
|
#### 出参
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `data.supplierId` | String | 供应商雪花 ID |
|
||||||
|
| `data.bankAccounts` | Array | 当前可读账户列表 |
|
||||||
|
| `data.bankAccounts[].status` | String | 草稿初始账户为 `DRAFT` |
|
||||||
|
| `data.bankAccounts[].isDefault` | String | 草稿初始账户为 `NO` |
|
||||||
|
| `data.updateTime` | String | 供应商主体并发版本 |
|
||||||
|
|
||||||
|
#### 请求示例
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /admin/supplier/items/2094000000000000000/account-info/list
|
||||||
|
Authorization: Bearer <admin-token>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"supplierId": "2094000000000000000",
|
||||||
|
"bankAccounts": [
|
||||||
|
{
|
||||||
|
"accountId": "2094000000000000001",
|
||||||
|
"accountType": "PERSONAL",
|
||||||
|
"bankName": "示例银行",
|
||||||
|
"bankBranch": null,
|
||||||
|
"accountNo": "6222000012345678",
|
||||||
|
"proofFileUrls": [],
|
||||||
|
"settleMode": null,
|
||||||
|
"accountPeriod": null,
|
||||||
|
"invoiceType": null,
|
||||||
|
"taxRate": null,
|
||||||
|
"status": "DRAFT",
|
||||||
|
"isDefault": "NO"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updateTime": "2026-08-29 17:01:01"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 空数据 / 降级响应
|
||||||
|
|
||||||
|
没有可读账户时 `data.bankAccounts` 返回空数组。可选文本字段为空时返回 `null`;已获附件读取权限且附件为空时 `proofFileUrls` 返回空数组。
|
||||||
|
|
||||||
|
#### 错误响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "code": 395001, "message": "供应商不存在", "success": false, "data": null }
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 业务边界
|
||||||
|
|
||||||
|
- 仅当供应商当前为 `DRAFT` 时才扩展读取草稿账户;其他状态的既有可见范围不变。
|
||||||
|
- 证明附件继续受独立权限和同步敏感读取审计约束;无权时不序列化附件原值。
|
||||||
|
- 查询不推进供应商或账户版本,不产生业务写副作用。
|
||||||
|
|
||||||
|
### 3. 查询收款账户详情 `GET /admin/supplier/bank-accounts/{accountId}/view`
|
||||||
|
|
||||||
|
**VO**: `SupplierBankAccountDetailRespVO`
|
||||||
|
|
||||||
|
#### 使用场景
|
||||||
|
|
||||||
|
草稿编辑页需要查看单个初始账户完整字段时,按列表返回的字符串 `accountId` 查询详情。
|
||||||
|
|
||||||
|
#### 入参
|
||||||
|
|
||||||
|
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||||
|
|---|---|---|---:|---|---|
|
||||||
|
| `accountId` | Path | String | 是 | 正整数 ID 字符串 | 目标账户 |
|
||||||
|
|
||||||
|
无 Query 参数,无请求体。
|
||||||
|
|
||||||
|
#### 出参
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `data.accountId` | String | 账户雪花 ID |
|
||||||
|
| `data.accountType` 等账户字段 | 对应类型/null | 完整账户业务值,6 个可选字段允许为空 |
|
||||||
|
| `data.status` | String | 草稿初始账户为 `DRAFT` |
|
||||||
|
| `data.isDefault` | String | 草稿初始账户为 `NO` |
|
||||||
|
| `data.updateTime` | String | 账户当前版本 |
|
||||||
|
|
||||||
|
#### 请求示例
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /admin/supplier/bank-accounts/2094000000000000001/view
|
||||||
|
Authorization: Bearer <admin-token>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"accountId": "2094000000000000001",
|
||||||
|
"accountType": "PERSONAL",
|
||||||
|
"bankName": "示例银行",
|
||||||
|
"bankBranch": null,
|
||||||
|
"accountNo": "6222000012345678",
|
||||||
|
"proofFileUrls": [],
|
||||||
|
"settleMode": null,
|
||||||
|
"accountPeriod": null,
|
||||||
|
"invoiceType": null,
|
||||||
|
"taxRate": null,
|
||||||
|
"status": "DRAFT",
|
||||||
|
"isDefault": "NO",
|
||||||
|
"updateTime": "2026-08-29 17:01:01"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 空数据 / 降级响应
|
||||||
|
|
||||||
|
目标账户不存在、已软删除或不在当前供应商状态允许的读取范围时,不返回部分对象;统一按不存在失败关闭。
|
||||||
|
|
||||||
|
#### 错误响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "code": 395001, "message": "供应商不存在", "success": false, "data": null }
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 业务边界
|
||||||
|
|
||||||
|
- 草稿详情可见性由所属供应商当前状态决定,不能仅凭 `accountId` 绕过主体边界。
|
||||||
|
- 完整账号沿用当前管理端授权语义;证明附件仍需独立权限与同步审计。
|
||||||
|
- 详情查询不改变账户、供应商、审批或默认账户状态。
|
||||||
|
|
||||||
|
## 四、契约约束与正确调用方式
|
||||||
|
|
||||||
|
- 编辑页先调用账户列表接口加载结算 table,再把用户实际编辑后的 0 或 1 项完整快照放入供应商更新请求的 `initialAccounts`。
|
||||||
|
- 用户未操作结算区域时可以省略 `initialAccounts`,避免无意义改写;明确清空时必须发送空数组。
|
||||||
|
- 保存必须同时发送非空 `changeReason` 与最近读取到的供应商 `expectedUpdateTime`。
|
||||||
|
- 账户业务字段使用与新建供应商一致的字段名;`supplierId`、`accountId` 按字符串处理,禁止转为 JavaScript Number。
|
||||||
|
|
||||||
|
## 五、数据库行为
|
||||||
|
|
||||||
|
- 草稿账户完整替换会把省略的 6 个可选字段持久化为空;重新查询不再回读旧值。
|
||||||
|
- 空数组对草稿初始账户执行软删除;供应商、账户和审计仍在同一服务事务内提交或回滚。
|
||||||
|
- 本次没有新增 migration、跨 schema 写入、Redis、MQ 或配置行为。
|
||||||
|
|
||||||
|
## 六、边界行为
|
||||||
|
|
||||||
|
- `accountType`、`bankName`、`accountNo` 仍为账户项必填字段;“可清空”只适用于其余 6 个可选字段。
|
||||||
|
- `MONTHLY` 与 `accountPeriod`、开票类型与税率的既有组合校验继续生效。
|
||||||
|
- 更新完整快照时未提供的可选字段保存为空,不是保持数据库旧值。
|
||||||
|
- 写失败时供应商、账户和审计均在同一事务回滚;过期版本和非草稿状态均零写入。
|
||||||
|
|
||||||
|
## 六.6、修改前后对比
|
||||||
|
|
||||||
|
| 项目 | 修改前 | 修改后 |
|
||||||
|
|---|---|---|
|
||||||
|
| 供应商编辑请求 | 无 `initialAccounts`,不能维护新建时的初始结算信息 | 可选完整快照:省略不改、空数组清空、1 项替换 |
|
||||||
|
| 草稿账户列表/详情 | `DRAFT` 初始账户不在管理端账户读取范围 | 所属供应商为 `DRAFT` 时可读回 |
|
||||||
|
| 可选字段清空 | 实体值虽置空,但默认更新策略可能保留数据库旧值 | 6 个可选字段显式持久化为空 |
|
||||||
|
| 审计与并发字段 | `changeReason`、`expectedUpdateTime` 必填 | 继续必填 |
|
||||||
|
|
||||||
|
## 六.7、影响评估
|
||||||
|
|
||||||
|
- **是否向后兼容**:是;不发送 `initialAccounts` 的原调用方保持原更新语义。
|
||||||
|
- **前端是否需要接入**:是;编辑页结算 table 需调用账户列表并按完整快照保存。
|
||||||
|
- **状态机影响**:无;仅草稿态开放聚合维护,其他状态继续走独立账户审批。
|
||||||
|
- **撤回影响**:撤回后编辑页应停止发送 `initialAccounts`,草稿账户也不再通过账户列表/详情读回。
|
||||||
|
|
||||||
|
## 七、不影响范围
|
||||||
|
|
||||||
|
- 不修改非草稿供应商的独立账户新增、审批、默认账户和账户状态机。
|
||||||
|
- 不修改合同独立登记接口、供应商提交审批流程或合同字段可空契约。
|
||||||
|
- 不新增错误码、数据库 migration、Gateway 路由、Redis、MQ、Nacos 或配置变更。
|
||||||
|
- 不修改任何前端源码;页面 table 排列和字段消费由前端按本契约处理。
|
||||||
|
|
||||||
|
## 八、测试环境已验证
|
||||||
|
|
||||||
|
- 新建草稿携带完整初始结算信息后,列表可读回相同字段。
|
||||||
|
- 草稿编辑把完整账户改为仅保留三个必填字段后,6 个可选字段保存并重新回读为空,账户 ID 保持不变。
|
||||||
|
- 缺少 `changeReason`、缺少 `expectedUpdateTime` 和使用过期版本均失败且账户零写入。
|
||||||
|
- 发送空数组后写响应和列表均为空;测试供应商删除后详情不可读,所有可恢复测试数据已清理。
|
||||||
|
|
||||||
|
## 十、相关文档
|
||||||
|
|
||||||
|
- Issue [#6669](https://git.1814.love:8443/wx/HL/issues/6669)
|
||||||
|
- 补充 Issue [#6676](https://git.1814.love:8443/wx/HL/issues/6676)
|
||||||
|
- PR [#6674](https://git.1814.love:8443/wx/HL/pulls/6674),合并提交 `35dba63d6a92159d933b38385fee057f617bdfed`
|
||||||
|
- PR [#6677](https://git.1814.love:8443/wx/HL/pulls/6677),合并提交 `af5ea05df3d7490c97e6f4329c145a4014396bee`
|
||||||
|
|
||||||
|
## 关联 / 联系人
|
||||||
|
|
||||||
|
- **后端负责人**:@lc
|
||||||
|
- **前端负责人**:@mmg
|
||||||
|
- **当前状态**:待前端处理
|
||||||
在新工单中引用
屏蔽一个用户