@@ -0,0 +1,327 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "7290"
|
||||
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: ""
|
||||
status_note: "后端已部署并通过 TEST Gateway 验证。前端须将合同编号文案改为“合同编号”,把十项字段设为必填,并移除新增、编辑的登记原因输入与 changeReason 传参;删除合同的原因仍必填。"
|
||||
updated_at: "2026-09-07"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 供应商合同:十项必填并移除登记原因
|
||||
|
||||
## 一、关键变化
|
||||
|
||||
- 新增、编辑合同均要求提交:合同名称、合同编号、合同状态、业务线、关联主合同、签署日期、自动续约、有效期开始、有效期结束、合同附件。
|
||||
- 页面字段 `contractNo` 的文案改为“合同编号”,不再显示“补合同编号”。
|
||||
- 新增、编辑不再要求登记原因,请移除原因输入框并停止发送 `changeReason`;旧调用方多传该字段仍兼容忽略。
|
||||
- 新增、编辑成功后不再产生供应商变更审计。合同删除接口及其必填原因、删除审计均不变。
|
||||
|
||||
本文覆盖此前 #6654、#6842 中“合同业务字段可空、新增或编辑原因必填”的旧口径。
|
||||
|
||||
## 二、变更接口清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | 新增供应商合同 | POST | `/admin/supplier/items/{supplierId}/contracts/add` | 请求校验与行为修改 | 十项必填,移除登记原因与新增审计 |
|
||||
| 2 | 编辑供应商合同 | PUT | `/admin/supplier/items/{supplierId}/contracts/{contractId}/update` | 请求校验与行为修改 | 十项必填,移除登记原因与编辑审计 |
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
### 1. 新增供应商合同 `POST /admin/supplier/items/{supplierId}/contracts/add`
|
||||
|
||||
**VO**: `SupplierContractCreateReqVO / SupplierContractRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
在已有供应商下新增一份完整合同,不再填写登记原因。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| `supplierId` | Path | String | 是 | 正整数 ID | 所属供应商 |
|
||||
| `contractName` | Body | String | 是 | 非空,最长 500 | 合同名称 |
|
||||
| `contractNo` | Body | String | 是 | 非空,最长 100 | 合同编号;页面不得再写“补合同编号” |
|
||||
| `status` | Body | String | 是 | `DRAFT` / `ACTIVE` / `SIGNED` / `EXPIRED` | 合同状态 |
|
||||
| `businessLine` | Body | String | 是 | 非空,最长 100 | 业务线 |
|
||||
| `relatedMainContract` | Body | String | 是 | 非空,最长 100 | 关联主合同引用 |
|
||||
| `signDate` | Body | String | 是 | `yyyy-MM-dd` | 签署日期 |
|
||||
| `autoRenew` | Body | Boolean | 是 | `true` / `false` | 自动续约;`false` 是有效值 |
|
||||
| `startDate` | Body | String | 是 | `yyyy-MM-dd` | 有效期开始 |
|
||||
| `endDate` | Body | String | 是 | 不早于 `startDate` | 有效期结束 |
|
||||
| `scanFileUrl` | Body | String | 是 | 非空,最长 1000 | 合同附件永久地址 |
|
||||
| `contractType` | Body | String/null | 否 | `FRAME` / `SINGLE_TRIP` / `PURCHASE` | 合同类型 |
|
||||
| `amount` | Body | String/null | 否 | 非负,最多 10 位整数和 2 位小数 | 合同金额 |
|
||||
| `pricingMode` | Body | String/null | 否 | 最长 100 | 计价方式 |
|
||||
| `settleCycle` | Body | String/null | 否 | 最长 32 | 结算周期 |
|
||||
| `remark` | Body | String/null | 否 | 最长 500 | 备注 |
|
||||
|
||||
`changeReason` 已从请求模型移除,不要再由新增表单组装。
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `code` / `message` / `success` | Integer / String / Boolean | 成功为 `200` / `成功` / `true` |
|
||||
| `data.contractId` | String | 合同 ID |
|
||||
| `data.contractName` / `contractNo` | String | 合同名称 / 合同编号 |
|
||||
| `data.status` / `businessLine` | String | 合同状态 / 业务线 |
|
||||
| `data.relatedMainContract` | String | 关联主合同 |
|
||||
| `data.signDate` / `startDate` / `endDate` | String | `yyyy-MM-dd` |
|
||||
| `data.autoRenew` | Boolean | 自动续约 |
|
||||
| `data.scanFileUrl` | String | 合同附件地址 |
|
||||
| `data.contractType` / `amount` / `pricingMode` / `settleCycle` / `remark` | 对应类型/null | 可选字段,响应结构不变 |
|
||||
| `data.updateTime` | String | 合同版本,`yyyy-MM-dd HH:mm:ss` |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"contractName": "年度服务合同",
|
||||
"contractNo": "HT-2026-001",
|
||||
"status": "SIGNED",
|
||||
"businessLine": "旅行服务",
|
||||
"relatedMainContract": "MAIN-2026-001",
|
||||
"signDate": "2026-09-07",
|
||||
"autoRenew": false,
|
||||
"startDate": "2026-09-07",
|
||||
"endDate": "2027-09-06",
|
||||
"scanFileUrl": "https://files.example.com/contracts/demo.pdf",
|
||||
"contractType": "FRAME",
|
||||
"amount": "1200.50",
|
||||
"pricingMode": "按团结算",
|
||||
"settleCycle": "MONTHLY",
|
||||
"remark": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"contractId": "2097000000000000001",
|
||||
"contractName": "年度服务合同",
|
||||
"contractNo": "HT-2026-001",
|
||||
"contractType": "FRAME",
|
||||
"signDate": "2026-09-07",
|
||||
"startDate": "2026-09-07",
|
||||
"endDate": "2027-09-06",
|
||||
"businessLine": "旅行服务",
|
||||
"relatedMainContract": "MAIN-2026-001",
|
||||
"autoRenew": false,
|
||||
"amount": "1200.50",
|
||||
"pricingMode": "按团结算",
|
||||
"settleCycle": "MONTHLY",
|
||||
"status": "SIGNED",
|
||||
"scanFileUrl": "https://files.example.com/contracts/demo.pdf",
|
||||
"remark": null,
|
||||
"updateTime": "2026-09-07 20:00:00"
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
没有空成功数据。十项必填字段缺少、为 `null` 或文本为空白时均失败,`data` 为 `null`。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{"code":400,"message":"合同编号不能为空","data":null,"success":false}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 前端提交前应同时校验十项必填;业务错误可能仍使用 HTTP 200,必须判断响应体 `code` 和 `success`。
|
||||
- `autoRenew=false` 不得被空值过滤器删除;`startDate` 不得晚于 `endDate`。
|
||||
- 权限、供应商状态、审批冻结、幂等和错误码均保持原规则。
|
||||
|
||||
### 2. 编辑供应商合同 `PUT /admin/supplier/items/{supplierId}/contracts/{contractId}/update`
|
||||
|
||||
**VO**: `SupplierContractUpdateReqVO / SupplierContractRespVO`
|
||||
|
||||
#### 使用场景
|
||||
|
||||
完整编辑一份已有合同,不再填写编辑原因。
|
||||
|
||||
#### 入参
|
||||
|
||||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||
|---|---|---|---|---|---|
|
||||
| `supplierId` | Path | String | 是 | 正整数 ID | 所属供应商 |
|
||||
| `contractId` | Path | String | 是 | 正整数 ID | 目标合同 |
|
||||
| `contractName` | Body | String | 是 | 非空,最长 500 | 合同名称 |
|
||||
| `contractNo` | Body | String | 是 | 非空,最长 100 | 合同编号 |
|
||||
| `status` | Body | String | 是 | `DRAFT` / `ACTIVE` / `SIGNED` / `EXPIRED` | 合同状态 |
|
||||
| `businessLine` | Body | String | 是 | 非空,最长 100 | 业务线 |
|
||||
| `relatedMainContract` | Body | String | 是 | 非空,最长 100 | 关联主合同引用 |
|
||||
| `signDate` | Body | String | 是 | `yyyy-MM-dd` | 签署日期 |
|
||||
| `autoRenew` | Body | Boolean | 是 | `true` / `false` | 自动续约 |
|
||||
| `startDate` | Body | String | 是 | `yyyy-MM-dd` | 有效期开始 |
|
||||
| `endDate` | Body | String | 是 | 不早于 `startDate` | 有效期结束 |
|
||||
| `scanFileUrl` | Body | String | 是 | 非空,最长 1000 | 合同附件永久地址 |
|
||||
| `expectedUpdateTime` | Body | String/null | 否 | `yyyy-MM-dd HH:mm:ss` | 传入时必须匹配合同当前版本 |
|
||||
| `contractType` / `amount` / `pricingMode` / `settleCycle` / `remark` | Body | 对应类型/null | 否 | 与新增接口一致 | 完整替换时原样回传需保留的可选值 |
|
||||
|
||||
`changeReason` 已从请求模型移除,不要再由编辑表单组装。
|
||||
|
||||
#### 出参
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `code` / `message` / `success` | Integer / String / Boolean | 成功为 `200` / `成功` / `true` |
|
||||
| `data.contractId` | String | 原合同 ID |
|
||||
| `data.contractName` / `contractNo` / `status` / `businessLine` | String | 编辑后的必填文本字段 |
|
||||
| `data.relatedMainContract` / `scanFileUrl` | String | 关联主合同 / 合同附件地址 |
|
||||
| `data.signDate` / `startDate` / `endDate` | String | 编辑后的日期 |
|
||||
| `data.autoRenew` | Boolean | 编辑后的自动续约值 |
|
||||
| `data.contractType` / `amount` / `pricingMode` / `settleCycle` / `remark` | 对应类型/null | 编辑后的可选字段 |
|
||||
| `data.updateTime` | String | 新合同版本,供下一次编辑或删除使用 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"contractName": "年度服务合同(续签)",
|
||||
"contractNo": "HT-2026-001-A",
|
||||
"status": "ACTIVE",
|
||||
"businessLine": "旅行服务",
|
||||
"relatedMainContract": "MAIN-2026-001",
|
||||
"signDate": "2026-09-07",
|
||||
"autoRenew": true,
|
||||
"startDate": "2026-09-07",
|
||||
"endDate": "2028-09-06",
|
||||
"scanFileUrl": "https://files.example.com/contracts/demo-a.pdf",
|
||||
"contractType": "FRAME",
|
||||
"amount": "1500.00",
|
||||
"pricingMode": "按团结算",
|
||||
"settleCycle": "MONTHLY",
|
||||
"remark": "续签",
|
||||
"expectedUpdateTime": "2026-09-07 20:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"contractId": "2097000000000000001",
|
||||
"contractName": "年度服务合同(续签)",
|
||||
"contractNo": "HT-2026-001-A",
|
||||
"contractType": "FRAME",
|
||||
"signDate": "2026-09-07",
|
||||
"startDate": "2026-09-07",
|
||||
"endDate": "2028-09-06",
|
||||
"businessLine": "旅行服务",
|
||||
"relatedMainContract": "MAIN-2026-001",
|
||||
"autoRenew": true,
|
||||
"amount": "1500.00",
|
||||
"pricingMode": "按团结算",
|
||||
"settleCycle": "MONTHLY",
|
||||
"status": "ACTIVE",
|
||||
"scanFileUrl": "https://files.example.com/contracts/demo-a.pdf",
|
||||
"remark": "续签",
|
||||
"updateTime": "2026-09-07 20:00:01"
|
||||
},
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 空数据 / 降级响应
|
||||
|
||||
没有空成功数据。历史合同仍可读取;编辑历史合同前须先补齐十项必填字段。
|
||||
|
||||
#### 错误响应
|
||||
|
||||
```json
|
||||
{"code":400,"message":"合同附件不能为空","data":null,"success":false}
|
||||
```
|
||||
|
||||
#### 业务边界
|
||||
|
||||
- 编辑仍是完整替换;十项必填字段必须全部提交,可选字段需按是否保留正确回传。
|
||||
- `expectedUpdateTime` 可省略,提交时应使用详情返回的合同版本;版本过期返回 `395014`。
|
||||
- 删除接口不在本次变化内,删除仍必须提交 `changeReason` 并产生删除审计。
|
||||
|
||||
## 四、契约约束与正确调用方式
|
||||
|
||||
1. 新增、编辑表单将十项字段全部标为必填,尤其不得把 `autoRenew=false` 当空值。
|
||||
2. 将 `contractNo` 的页面标签统一改为“合同编号”。
|
||||
3. 移除新增、编辑的登记原因输入与校验,请求体不再组装 `changeReason`。
|
||||
4. 编辑时从详情的 `contracts[]` 完整回填并提交;隐藏的可选字段继续原样保留。
|
||||
5. 删除合同继续沿用原因弹框和原 DELETE 请求体,不要一并移除。
|
||||
|
||||
## 五、数据库行为
|
||||
|
||||
新增、编辑成功后保存完整合同值,但不新增供应商变更审计;校验失败时合同与审计均不变化。删除仍为软删除并保留原删除审计。本次无表结构或历史数据迁移。
|
||||
|
||||
## 六、边界行为
|
||||
|
||||
- 缺少任一必填字段:`code=400`、`success=false`,不会写入或修改合同。
|
||||
- 未登录:`code=401`;无写权限:`395002`;合同不存在或归属错误:`395051`;日期倒置:`395054`;无实际变化:`395057`。
|
||||
- 历史合同可能含空字段,读取不受影响;再次编辑时须补齐十项。
|
||||
- 旧请求额外携带 `changeReason` 不会失败,但后端不保存该值,也不产生新增、编辑审计。
|
||||
|
||||
## 六.6、修改前后对比
|
||||
|
||||
| 字段 / 行为 | 修改前 | 修改后 |
|
||||
|---|---|---|
|
||||
| 十项业务字段 | 均可省略或清空 | 新增、编辑全部必填 |
|
||||
| `contractNo` 页面文案 | 补合同编号 | 合同编号 |
|
||||
| 新增、编辑 `changeReason` | 必填 | 不需要;旧请求多传兼容忽略 |
|
||||
| 新增、编辑供应商变更审计 | 产生审计 | 不产生审计 |
|
||||
| 删除原因与审计 | 原因必填并产生审计 | 不变 |
|
||||
|
||||
## 六.7、影响评估
|
||||
|
||||
- **是否破坏向后兼容**:对缺少十项中任一字段的旧新增、编辑请求是收紧变化;旧请求多传 `changeReason` 仍兼容。
|
||||
- **前端是否必须同步上线**:是。必须调整必填、文案和新增/编辑原因交互。
|
||||
- **前端 workaround 清理点**:删除新增、编辑原因弹框及 `changeReason` 组装;保留删除原因流程。
|
||||
|
||||
## 七、不影响范围
|
||||
|
||||
- 仅影响管理后台供应商合同新增、编辑。
|
||||
- 不修改合同删除、供应商主体、收款账户、小程序接口、响应字段、数据库结构及历史合同读取。
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
- POST 与 PUT 各对十项字段逐项省略,共 20 个请求均返回 `code=400`,失败路径零写入。
|
||||
- 不带 `changeReason` 的新增、编辑均成功;`autoRenew=false` 正常保存,旧请求多传 `changeReason` 仍兼容。
|
||||
- 新增、编辑对应的供应商变更审计均为 0;临时合同已删除,原删除审计保持存在。
|
||||
|
||||
**当前状态:后端已部署并验证;待前端处理。**
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
- [Issue #7290](https://git.1814.love:8443/wx/HL/issues/7290)
|
||||
- [PR #7298](https://git.1814.love:8443/wx/HL/pulls/7298)
|
||||
- [被本文覆盖的合同旧口径 #6842](https://git.1814.love:8443/wx/HL/issues/6842)
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
### 链接
|
||||
|
||||
- **Issue**: [#7290](https://git.1814.love:8443/wx/HL/issues/7290)
|
||||
- **PR**: [#7298](https://git.1814.love:8443/wx/HL/pulls/7298)
|
||||
- **Merge commit**: [29ee134f330ca9524d6e74090a80aea3594b334e](https://git.1814.love:8443/wx/HL/commit/29ee134f330ca9524d6e74090a80aea3594b334e)
|
||||
|
||||
### 联系人
|
||||
|
||||
- **后端负责人**: @lc
|
||||
在新工单中引用
屏蔽一个用户