@@ -0,0 +1,373 @@
|
|||||||
|
---
|
||||||
|
schema: "hl-changelog/v2"
|
||||||
|
ticket: "6842"
|
||||||
|
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: "PR #6858 已合并 dev-v3,hl-resource-service 已部署提交 5546d7907c6eda9b372b4639094f84e568de6496。TEST Gateway 已验证完整字段与全空业务字段合同的新增、更新、详情回读,以及单个 PDF 上传、预览、下载和清理。当前状态:后端已就绪,前端待处理。"
|
||||||
|
updated_at: "2026-08-31"
|
||||||
|
base: "dev-v3"
|
||||||
|
---
|
||||||
|
|
||||||
|
# 供应商补充合同字段与附件
|
||||||
|
|
||||||
|
供应商补充合同新增 `businessLine`、`relatedMainContract`、`autoRenew`,并允许写入 `SIGNED`(已签约)。所有合同业务字段均可为空,只有 `changeReason` 继续必填。
|
||||||
|
|
||||||
|
管理端登记页仅展示补合同编号、状态、合同名称、业务线、有效期、签署日期、关联主合同、自动续约和单个 Word/PDF 附件;其他兼容字段隐藏。
|
||||||
|
|
||||||
|
## 二、变更接口清单
|
||||||
|
|
||||||
|
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||||
|
|---:|---|---|---|---|---|
|
||||||
|
| 1 | 独立登记供应商合同 | POST | `/admin/supplier/items/{supplierId}/contracts/add` | 扩展请求与响应 | 增加三个字段,状态支持 `SIGNED` |
|
||||||
|
| 2 | 独立更新供应商合同 | PUT | `/admin/supplier/items/{supplierId}/contracts/{contractId}/update` | 扩展请求与响应 | 新字段支持补录、清空和 `false` |
|
||||||
|
| 3 | 查询供应商基本信息 | GET | `/admin/supplier/items/{supplierId}/basic-info/view` | 扩展响应 | `contracts[]` 完整回读补充合同字段 |
|
||||||
|
|
||||||
|
## 三、接口详情
|
||||||
|
|
||||||
|
### 1. 独立登记供应商合同 `POST /admin/supplier/items/{supplierId}/contracts/add`
|
||||||
|
|
||||||
|
**VO**: `SupplierContractCreateReqVO / SupplierContractRespVO`
|
||||||
|
|
||||||
|
#### 使用场景
|
||||||
|
|
||||||
|
供应商已创建后登记一份补充合同;业务资料未齐时也可只提交审计原因,稍后再补录。
|
||||||
|
|
||||||
|
#### 入参
|
||||||
|
|
||||||
|
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||||
|
|---|---|---|---:|---|---|
|
||||||
|
| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 |
|
||||||
|
| `contractNo` | Body | String/null | 否 | 最长 100 | 补合同编号 |
|
||||||
|
| `status` | Body | String/null | 否 | `DRAFT` / `ACTIVE` / `SIGNED` / `EXPIRED` | `SIGNED` 显示为“已签约” |
|
||||||
|
| `contractName` | Body | String/null | 否 | 最长 500 | 合同名称 |
|
||||||
|
| `businessLine` | Body | String/null | 否 | 最长 100 | 业务线,自由文本 |
|
||||||
|
| `startDate` | Body | String/null | 否 | `yyyy-MM-dd` | 有效期开始日 |
|
||||||
|
| `endDate` | Body | String/null | 否 | `yyyy-MM-dd` | 有效期结束日;两端都有值时不得早于开始日 |
|
||||||
|
| `signDate` | Body | String/null | 否 | `yyyy-MM-dd` | 合同签署日期 |
|
||||||
|
| `relatedMainContract` | Body | String/null | 否 | 最长 100 | 关联主合同外部引用 |
|
||||||
|
| `autoRenew` | Body | Boolean/null | 否 | `true` / `false` / `null` | 是 / 否 / 未登记 |
|
||||||
|
| `scanFileUrl` | Body | String/null | 否 | 最长 1000 | 文件中心确认上传后返回的永久 `ossUrl` |
|
||||||
|
| `changeReason` | Body | String | 是 | 去空白后非空,最长 500 | 登记原因,写入审计 |
|
||||||
|
|
||||||
|
`contractType`、`amount`、`pricingMode`、`settleCycle`、`remark` 仍兼容但本页面隐藏,也均可为空。
|
||||||
|
|
||||||
|
#### 出参
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `data.contractId` | String | 合同 ID |
|
||||||
|
| `data.contractNo` | String/null | 补合同编号 |
|
||||||
|
| `data.status` | String/null | 包含新增可写值 `SIGNED` |
|
||||||
|
| `data.contractName` | String/null | 合同名称 |
|
||||||
|
| `data.businessLine` | String/null | 业务线 |
|
||||||
|
| `data.startDate` / `data.endDate` | String/null | 有效期日期 |
|
||||||
|
| `data.signDate` | String/null | 签署日期 |
|
||||||
|
| `data.relatedMainContract` | String/null | 关联主合同 |
|
||||||
|
| `data.autoRenew` | Boolean/null | 自动续约三态值 |
|
||||||
|
| `data.scanFileUrl` | String/null | 合同附件永久地址 |
|
||||||
|
| `data.updateTime` | String | 当前合同版本,格式 `yyyy-MM-dd HH:mm:ss` |
|
||||||
|
|
||||||
|
#### 请求示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"contractNo": "SHCT2025070102599446",
|
||||||
|
"status": "SIGNED",
|
||||||
|
"contractName": "内蒙古牵手草原国际旅行社有限公司额外后返",
|
||||||
|
"businessLine": null,
|
||||||
|
"startDate": "2010-01-01",
|
||||||
|
"endDate": "2099-12-31",
|
||||||
|
"signDate": "2025-07-01",
|
||||||
|
"relatedMainContract": "2185933",
|
||||||
|
"autoRenew": true,
|
||||||
|
"scanFileUrl": "https://files.example.com/supplier-contract/example.pdf",
|
||||||
|
"changeReason": "补录已签约合同"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"contractId": "2095000000000000001",
|
||||||
|
"contractNo": "SHCT2025070102599446",
|
||||||
|
"status": "SIGNED",
|
||||||
|
"contractName": "内蒙古牵手草原国际旅行社有限公司额外后返",
|
||||||
|
"businessLine": null,
|
||||||
|
"startDate": "2010-01-01",
|
||||||
|
"endDate": "2099-12-31",
|
||||||
|
"signDate": "2025-07-01",
|
||||||
|
"relatedMainContract": "2185933",
|
||||||
|
"autoRenew": true,
|
||||||
|
"scanFileUrl": "https://files.example.com/supplier-contract/example.pdf",
|
||||||
|
"updateTime": "2026-08-31 12:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 空数据 / 降级响应
|
||||||
|
|
||||||
|
仅提交 `changeReason` 也可成功;所有合同业务字段返回 `null`,前端不得补默认状态或日期。
|
||||||
|
|
||||||
|
#### 错误响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 400,
|
||||||
|
"message": "变更原因不能为空",
|
||||||
|
"success": false,
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 业务边界
|
||||||
|
|
||||||
|
- 所有合同业务字段可空;`changeReason` 不属于业务展示字段,继续必填。
|
||||||
|
- `startDate`、`endDate` 同时有值时才校验日期先后。
|
||||||
|
- `scanFileUrl` 只保存一个附件永久地址;上传、预览、下载复用文件中心。
|
||||||
|
|
||||||
|
### 2. 独立更新供应商合同 `PUT /admin/supplier/items/{supplierId}/contracts/{contractId}/update`
|
||||||
|
|
||||||
|
**VO**: `SupplierContractUpdateReqVO / SupplierContractRespVO`
|
||||||
|
|
||||||
|
#### 使用场景
|
||||||
|
|
||||||
|
补齐、修改或清空已登记合同。该接口为完整替换,省略或传 `null` 会清空对应字段。
|
||||||
|
|
||||||
|
#### 入参
|
||||||
|
|
||||||
|
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||||
|
|---|---|---|---:|---|---|
|
||||||
|
| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 |
|
||||||
|
| `contractId` | Path | String | 是 | 正整数 ID 字符串 | 目标合同 |
|
||||||
|
| 新增接口全部业务字段 | Body | 对应类型/null | 否 | 与新增一致 | 完整替换;`autoRenew=false` 会保留为否 |
|
||||||
|
| `expectedUpdateTime` | Body | String/null | 否 | `yyyy-MM-dd HH:mm:ss` | 提供时必须匹配当前版本 |
|
||||||
|
| `changeReason` | Body | String | 是 | 去空白后非空,最长 500 | 更新原因 |
|
||||||
|
|
||||||
|
#### 出参
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `data.contractId` | String | 原合同 ID |
|
||||||
|
| `data.businessLine` | String/null | 更新后的业务线,空白规范为 `null` |
|
||||||
|
| `data.relatedMainContract` | String/null | 更新后的关联主合同 |
|
||||||
|
| `data.autoRenew` | Boolean/null | 精确保留 `true`、`false` 或 `null` |
|
||||||
|
| `data.status` | String/null | 可返回 `SIGNED` |
|
||||||
|
| 其余合同业务字段 | 对应类型/null | 完整替换后的值 |
|
||||||
|
| `data.updateTime` | String | 更新后的合同版本 |
|
||||||
|
|
||||||
|
#### 请求示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"contractNo": "SHCT2025070102599446",
|
||||||
|
"status": "SIGNED",
|
||||||
|
"contractName": "内蒙古牵手草原国际旅行社有限公司额外后返",
|
||||||
|
"businessLine": null,
|
||||||
|
"startDate": "2010-01-01",
|
||||||
|
"endDate": "2099-12-31",
|
||||||
|
"signDate": "2025-07-01",
|
||||||
|
"relatedMainContract": null,
|
||||||
|
"autoRenew": false,
|
||||||
|
"scanFileUrl": "https://files.example.com/supplier-contract/example.pdf",
|
||||||
|
"changeReason": "调整自动续约信息"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"contractId": "2095000000000000001",
|
||||||
|
"contractNo": "SHCT2025070102599446",
|
||||||
|
"status": "SIGNED",
|
||||||
|
"businessLine": null,
|
||||||
|
"relatedMainContract": null,
|
||||||
|
"autoRenew": false,
|
||||||
|
"updateTime": "2026-08-31 12:00:01"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 空数据 / 降级响应
|
||||||
|
|
||||||
|
仅提交 `changeReason` 可把全部业务字段清空;与当前内容完全相同时拒绝空更新,不生成新版本。
|
||||||
|
|
||||||
|
#### 错误响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 395054,
|
||||||
|
"message": "合同有效期开始日期不能晚于结束日期",
|
||||||
|
"success": false,
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 业务边界
|
||||||
|
|
||||||
|
- 页面隐藏兼容字段时,编辑既有合同应从详情原样回传其 `contractType`、`amount`、`pricingMode`、`settleCycle`、`remark`,避免完整替换误清历史值。
|
||||||
|
- `autoRenew=false` 是有效业务值,不能按空值过滤。
|
||||||
|
- `expectedUpdateTime` 可省略;提供过期值时返回 `395014`,合同保持不变。
|
||||||
|
|
||||||
|
### 3. 查询供应商基本信息 `GET /admin/supplier/items/{supplierId}/basic-info/view`
|
||||||
|
|
||||||
|
**VO**: `SupplierBasicInfoRespVO / SupplierContractRespVO`
|
||||||
|
|
||||||
|
#### 使用场景
|
||||||
|
|
||||||
|
进入供应商编辑或详情页时,从 `data.contracts[]` 回显合同表格和附件操作。
|
||||||
|
|
||||||
|
#### 入参
|
||||||
|
|
||||||
|
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||||||
|
|---|---|---|---:|---|---|
|
||||||
|
| `supplierId` | Path | String | 是 | 正整数 ID 字符串 | 目标供应商 |
|
||||||
|
|
||||||
|
#### 出参
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `data.contracts` | Array | 当前有效合同,按合同 ID 升序 |
|
||||||
|
| `data.contracts[].businessLine` | String/null | 业务线 |
|
||||||
|
| `data.contracts[].relatedMainContract` | String/null | 关联主合同 |
|
||||||
|
| `data.contracts[].autoRenew` | Boolean/null | 自动续约三态值 |
|
||||||
|
| `data.contracts[].status` | String/null | `SIGNED` 显示为“已签约” |
|
||||||
|
| `data.contracts[].scanFileUrl` | String/null | 单个合同附件永久地址 |
|
||||||
|
| 其余合同字段 | 对应类型/null | 与新增、更新响应一致 |
|
||||||
|
|
||||||
|
#### 请求示例
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /admin/supplier/items/2095000000000000000/basic-info/view
|
||||||
|
Authorization: Bearer <admin-token>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"message": "成功",
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"supplierId": "2095000000000000000",
|
||||||
|
"contracts": [
|
||||||
|
{
|
||||||
|
"contractId": "2095000000000000001",
|
||||||
|
"contractNo": "SHCT2025070102599446",
|
||||||
|
"status": "SIGNED",
|
||||||
|
"contractName": "内蒙古牵手草原国际旅行社有限公司额外后返",
|
||||||
|
"businessLine": null,
|
||||||
|
"startDate": "2010-01-01",
|
||||||
|
"endDate": "2099-12-31",
|
||||||
|
"signDate": "2025-07-01",
|
||||||
|
"relatedMainContract": "2185933",
|
||||||
|
"autoRenew": true,
|
||||||
|
"scanFileUrl": "https://files.example.com/supplier-contract/example.pdf"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 空数据 / 降级响应
|
||||||
|
|
||||||
|
没有合同记录时 `contracts=[]`;合同存在但某项未登记时,对应字段为 `null`。
|
||||||
|
|
||||||
|
#### 错误响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 395001,
|
||||||
|
"message": "供应商不存在",
|
||||||
|
"success": false,
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 业务边界
|
||||||
|
|
||||||
|
- 日期均为上海业务日字符串,前端按 `yyyy-MM-dd` 原样展示,不做 UTC 日期转换。
|
||||||
|
- 查询只返回未删除合同;附件为空时隐藏预览、下载操作。
|
||||||
|
- 未登录请求由 Gateway 返回业务码 `401`。
|
||||||
|
|
||||||
|
## 四、契约约束与正确调用方式
|
||||||
|
|
||||||
|
1. 表格列固定映射为 `contractNo`、`status`、`contractName`、`businessLine`、`startDate/endDate`、`signDate`、`relatedMainContract`、`autoRenew`、`scanFileUrl`;`SIGNED` 展示“已签约”。
|
||||||
|
2. `startDate/endDate` 直接按上海日历日拼成有效期;`autoRenew=true` 可显示“到期自动续约”,`false` 显示“否”,`null` 显示未登记占位。
|
||||||
|
3. 附件复用文件中心:申请上传凭证 `POST /admin/file/upload/token`,按返回模式上传后调用 `POST /admin/file/upload/confirm`,把确认响应的 `data.ossUrl` 写入 `scanFileUrl`。组件仅保留一个 `.doc`、`.docx` 或 `.pdf` 文件。
|
||||||
|
4. 预览使用带登录态的 `GET /admin/file/preview-by-url?url={encodeURIComponent(scanFileUrl)}`;下载直接访问 `scanFileUrl`。
|
||||||
|
5. 本页面隐藏 `contractType`、`amount`、`pricingMode`、`settleCycle`、`remark`;编辑历史合同时仍从详情原样回传,避免完整替换清空旧值。
|
||||||
|
|
||||||
|
## 五、数据库行为
|
||||||
|
|
||||||
|
这里只约定外部可观察结果:新增或更新成功后,再次请求基本信息详情可读到相同字段;未填写值返回 `null`,`autoRenew=false` 不会丢失。失败响应不产生部分合同变更。
|
||||||
|
|
||||||
|
## 六、边界行为
|
||||||
|
|
||||||
|
- 所有合同业务字段可空,只有新增、更新、删除操作的 `changeReason` 必填。
|
||||||
|
- `SIGNED` 仅是新增可写状态,不改变既有 `DRAFT`、`ACTIVE`、`EXPIRED` 和历史 `TERMINATED` 的兼容读取。
|
||||||
|
- 日期两端都有值且开始日晚于结束日时返回 `395054`,整次更新零写入。
|
||||||
|
- 附件字段为单值;前端负责限制为一个 Word/PDF,并在替换附件后提交新的永久地址。
|
||||||
|
- 写接口沿用既有角色、权限、幂等、锁和审计规则,无新增错误码。
|
||||||
|
|
||||||
|
## 六.6、修改前后对比
|
||||||
|
|
||||||
|
| 项目 | 修改前 | 修改后 |
|
||||||
|
|---|---|---|
|
||||||
|
| 业务线、关联主合同、自动续约 | 无字段 | 新增 `businessLine`、`relatedMainContract`、`autoRenew`,均可空 |
|
||||||
|
| 合同状态 | 可写 `DRAFT` / `ACTIVE` / `EXPIRED` | 追加可写 `SIGNED`(已签约) |
|
||||||
|
| 详情回读 | 无新增三字段 | `contracts[]` 完整回读新增三字段 |
|
||||||
|
| 其他合同业务字段 | 可空 | 继续可空,语义不变 |
|
||||||
|
|
||||||
|
## 六.7、影响评估
|
||||||
|
|
||||||
|
- **是否破坏向后兼容**:否,均为可选字段和状态枚举扩展。
|
||||||
|
- **前端是否必须同步上线**:是,需要新增列、附件控件和 `SIGNED` 中文映射,并隐藏非目标字段。
|
||||||
|
- **前端 workaround 清理点**:不要在本地拼装缺失字段;以详情 `contracts[]` 为回显真相。
|
||||||
|
|
||||||
|
## 七、不影响范围
|
||||||
|
|
||||||
|
- 不修改供应商主体、联系人、资质、结算账户、审批和归档接口。
|
||||||
|
- 不把合同并回供应商注册聚合;仍先取得 `supplierId`,再调用独立合同接口。
|
||||||
|
- 不新增 Gateway 路由、权限点、配置、Redis 或 MQ 契约。
|
||||||
|
|
||||||
|
## 八、测试环境已验证
|
||||||
|
|
||||||
|
- 已在 TEST Gateway 验证完整字段和仅含 `changeReason` 的合同均可新增并跨请求回读;`SIGNED`、`null`、`false`、日期错误零写入均符合本契约。
|
||||||
|
- 已验证一个 PDF 经文件中心上传后可预览、下载,验收产生的合同、附件和会话均已清理。
|
||||||
|
|
||||||
|
## 当前状态
|
||||||
|
|
||||||
|
- 后端:已部署并已验证。
|
||||||
|
- 前端:待处理。
|
||||||
|
|
||||||
|
## 十、相关文档
|
||||||
|
|
||||||
|
- Issue:[#6842](https://git.1814.love:8443/wx/HL/issues/6842)
|
||||||
|
- 后端 PR:[#6858](https://git.1814.love:8443/wx/HL/pulls/6858)
|
||||||
|
- 合并提交:[5546d790](https://git.1814.love:8443/wx/HL/commit/5546d7907c6eda9b372b4639094f84e568de6496)
|
||||||
|
|
||||||
|
## 关联 / 联系人
|
||||||
|
|
||||||
|
- **Issue**: [#6842](https://git.1814.love:8443/wx/HL/issues/6842)
|
||||||
|
- **PR**: [#6858](https://git.1814.love:8443/wx/HL/pulls/6858)
|
||||||
|
- **后端负责人**: @lc
|
||||||
在新工单中引用
屏蔽一个用户