From 0b86d2593f7435d3f44929ac35d30062d26eb506 Mon Sep 17 00:00:00 2001 From: lc Date: Mon, 7 Sep 2026 19:53:41 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E4=B8=8B=E5=8F=91=E4=BE=9B=E5=BA=94?= =?UTF-8?q?=E5=95=86=E5=90=88=E5=90=8C=E5=BF=85=E5=A1=AB=E4=B8=8E=E5=8E=BB?= =?UTF-8?q?=E5=8E=9F=E5=9B=A0=E5=A5=91=E7=BA=A6=EF=BC=88#7290=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ˆ同十项必填并移除登记原因-修改接口-管理后台.md | 327 ++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 changelogs-v2/2026-09/07_7290_供应商合同十项必填并移除登记原因-修改接口-管理后台.md diff --git a/changelogs-v2/2026-09/07_7290_供应商合同十项必填并移除登记原因-修改接口-管理后台.md b/changelogs-v2/2026-09/07_7290_供应商合同十项必填并移除登记原因-修改接口-管理后台.md new file mode 100644 index 00000000..440a5658 --- /dev/null +++ b/changelogs-v2/2026-09/07_7290_供应商合同十项必填并移除登记原因-修改接口-管理后台.md @@ -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