14 KiB
14 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 7290 | 供应商合同十项必填并移除登记原因 | admin | lc(GIT) | 修改接口 | deployed | verified | verified | mmg | 87cf8ba8 | 2026-09-07 | 前端已交付并验证(commit 87cf8ba8):SupplierContractEditModal 十项转必填(文本 trim 非空/枚举日期判空/autoRenew 按 ===true-false 不把 false 当空,endDate 合并必填+不早于开始日期单条 rule),contractNo label 补合同编号→合同编号;删登记/修改原因输入+changeReasonRule+buildBody 不再组装 changeReason;必填恒携带、可选(contractType/amount/pricingMode/settleCycle/remark)保持新增省略/编辑整份替换,expectedUpdateTime 围栏与 395014/395051 提示不变;api add/update JSDoc 改新口径,delete 与删除审计流程零改动。目标 spec 24/24 绿+supplier 域 183/183 绿+checkpoint 全绿(Vitest 全量+生产构建)。 | 2026-09-07 | 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 |
请求示例
{
"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
}
响应示例
{
"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。
错误响应
{"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 | 新合同版本,供下一次编辑或删除使用 |
请求示例
{
"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"
}
响应示例
{
"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
}
空数据 / 降级响应
没有空成功数据。历史合同仍可读取;编辑历史合同前须先补齐十项必填字段。
错误响应
{"code":400,"message":"合同附件不能为空","data":null,"success":false}
业务边界
- 编辑仍是完整替换;十项必填字段必须全部提交,可选字段需按是否保留正确回传。
expectedUpdateTime可省略,提交时应使用详情返回的合同版本;版本过期返回395014。- 删除接口不在本次变化内,删除仍必须提交
changeReason并产生删除审计。
四、契约约束与正确调用方式
- 新增、编辑表单将十项字段全部标为必填,尤其不得把
autoRenew=false当空值。 - 将
contractNo的页面标签统一改为“合同编号”。 - 移除新增、编辑的登记原因输入与校验,请求体不再组装
changeReason。 - 编辑时从详情的
contracts[]完整回填并提交;隐藏的可选字段继续原样保留。 - 删除合同继续沿用原因弹框和原 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
- PR: #7298
- Merge commit: 29ee134f330ca9524d6e74090a80aea3594b334e
联系人
- 后端负责人: @lc