From 8696bbb08394437e7ad3117c635717d14377e537 Mon Sep 17 00:00:00 2001 From: lc Date: Fri, 4 Sep 2026 16:52:18 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=BE=9B=E5=BA=94=E5=95=86?= =?UTF-8?q?=E6=96=B0=E5=BB=BA=E4=BF=AE=E6=94=B9=E5=BF=85=E5=A1=AB=E8=B5=84?= =?UTF-8?q?=E6=96=99=E8=AF=B4=E6=98=8E=EF=BC=88#7087=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...”商新建修改必填资料校验-修改接口-管理后台.md | 267 ++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 changelogs-v2/2026-09/04_7087_供应商新建修改必填资料校验-修改接口-管理后台.md diff --git a/changelogs-v2/2026-09/04_7087_供应商新建修改必填资料校验-修改接口-管理后台.md b/changelogs-v2/2026-09/04_7087_供应商新建修改必填资料校验-修改接口-管理后台.md new file mode 100644 index 00000000..2512a167 --- /dev/null +++ b/changelogs-v2/2026-09/04_7087_供应商新建修改必填资料校验-修改接口-管理后台.md @@ -0,0 +1,267 @@ +--- +schema: "hl-changelog/v2" +ticket: "7087" +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;前端需为供应商新建和编辑表单补齐主体资料、联系人及结算账户必填校验。" +updated_at: "2026-09-04" +base: "dev-v3" +--- + +# 供应商模块:新建与修改补齐必填资料校验 + +`POST /admin/supplier/items/add` 新建时必须一次提交完整资料;`PUT /admin/supplier/items/{supplierId}/update` 仍是增量接口,但保存后的供应商聚合必须完整。前端需同步补齐表单必填标识和提交前校验。 + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|---|---|---|---|---| +| 1 | 新建供应商草稿 | POST | `/admin/supplier/items/add` | 必填校验收紧 | 主体资料完整,且至少一名联系人、一个初始账户 | +| 2 | 修改供应商资料 | PUT | `/admin/supplier/items/{supplierId}/update` | 聚合完整性校验 | 省略字段保留现值;显式空类型、联系人或账户拒绝 | + +## 三、接口详情 + +### 1. 新建供应商草稿 `POST /admin/supplier/items/add` + +**VO**: `SupplierDraftSaveReqVO → SupplierWriteRespVO` + +#### 使用场景 + +管理端完成供应商新建表单后保存草稿。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| `fullName` | Body | String | 是 | 非空,最长 500 | 供应商全称 | +| `taxNo` | Body | String | 是 | 合法主体证件号 | 统一社会信用代码 | +| `types` | Body | Array | 是 | 至少 1 项,最多 15 项 | `typeCode` 取 `supplier_type` 生效字典值 | +| `legalRepresentative` | Body | String | 是 | 非空 | 法定代表人 | +| `legalRepresentativeIdNo` | Body | String | 是 | 合法 18 位居民身份证号 | 法人身份证号 | +| `legalRepresentativeIdCardFrontUrl` | Body | String | 是 | 公网 HTTPS 永久地址 | 身份证人像面 | +| `legalRepresentativeIdCardBackUrl` | Body | String | 是 | 公网 HTTPS 永久地址 | 身份证国徽面 | +| `contactPhone` | Body | String | 是 | 合法手机号、座机或 400/800 号码 | 法人联系电话 | +| `establishDate` | Body | String | 是 | `yyyy-MM-dd`,不得晚于当天 | 成立日期 | +| `balance` | Body | Number | 是 | 最多 16 位整数、2 位小数 | 余额,可为正数、0 或负数 | +| `paymentType` | Body | String | 是 | `supplier_payment_type` 生效字典值 | 支付类型 | +| `mainCooperation` | Body | String | 是 | 非空 | 主要合作内容 | +| `licenseImageUrl` | Body | String | 是 | 非空 | 营业执照影像地址 | +| `address` | Body | String | 是 | 非空,最长 500 | 注册地址 | +| `contacts` | Body | Array | 是 | 至少 1 项,最多 100 项 | 每项填写姓名、电话及 `sup_content_role` 角色 | +| `initialAccounts` | Body | Array | 是 | 当前必须且只能 1 项 | 每项填写账户类型、银行和账号 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| `data.supplierId` | String | 供应商 ID | +| `data.supplierNo` | String | 供应商编号 | +| `data.status` | String | 新建成功为 `DRAFT` | +| `data.initialAccounts` | Array | 初始账户摘要 | +| `data.updateTime` | String | 后续修改使用的并发版本 | + +#### 请求示例 + +```json +{ + "fullName": "示例供应商有限公司", + "taxNo": "91350211M000100Y46", + "types": [{"typeCode": "HOTEL"}], + "legalRepresentative": "张三", + "legalRepresentativeIdNo": "11010519491231002X", + "legalRepresentativeIdCardFrontUrl": "https://example.com/supplier/id-front.jpg", + "legalRepresentativeIdCardBackUrl": "https://example.com/supplier/id-back.jpg", + "contactPhone": "13800138000", + "establishDate": "2020-01-02", + "balance": 0, + "paymentType": "1", + "mainCooperation": "酒店资源合作", + "licenseImageUrl": "https://example.com/supplier/license.jpg", + "address": "厦门市思明区示例路 1 号", + "contacts": [{"contactName": "李四", "contactPhone": "13800138001", "contactRole": "contentBus", "isPrimary": true}], + "initialAccounts": [{"accountType": "CORPORATE", "bankName": "示例银行", "accountNo": "6222000012345678"}] +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "supplierId": "2095000000000000001", + "supplierNo": "SUP2095000000000000001", + "status": "DRAFT", + "initialAccounts": [{"accountId": "2095000000000000002", "status": "DRAFT"}], + "updateTime": "2026-09-04 16:48:49" + } +} +``` + +#### 空数据 / 降级响应 + +写接口没有空数据成功或降级成功;任一必填项缺失时返回失败响应。 + +#### 错误响应 + +```json +{"code":400,"message":"联系人不能为空","data":null,"success":false} +``` + +#### 业务边界 + +- 未登录返回业务码 `401`;写入仍要求 `FINANCE` 或 `SUPER_ADMIN` 及 `supplier:create` 权限。 +- `types`、`contacts`、`initialAccounts` 传 `null`、省略或空数组均视为缺失。 +- 校验失败不创建供应商或子项;响应可能使用 HTTP 200,必须同时检查 `code` 与 `success`。 + +### 2. 修改供应商资料 `PUT /admin/supplier/items/{supplierId}/update` + +**VO**: `SupplierUpdateReqVO → SupplierWriteRespVO` + +#### 使用场景 + +管理端编辑既有供应商资料并按最新版本保存。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| `supplierId` | Path | String | 是 | 正整数 ID | 目标供应商 | +| `expectedUpdateTime` | Body | String | 是 | `yyyy-MM-dd HH:mm:ss` | 取详情最新 `updateTime` | +| 主体必填资料 | Body | 原类型 | 条件必填 | 与新建接口相同 | 省略表示保留现值;保存后的有效值必须完整 | +| `types` | Body | Array | 条件必填 | 显式提交时至少 1 项 | 省略保留存量,`[]` 拒绝 | +| `contacts` | Body | Array | 条件必填 | 显式提交时至少 1 项 | 省略保留存量,`[]` 拒绝 | +| `initialAccounts` | Body | Array | 条件必填 | 显式提交时当前必须且只能 1 项 | 省略保留存量,`[]` 拒绝 | +| `changeReason` | Body | String | 条件必填 | 最长 500 | `DRAFT` 可省略,其他可修改状态沿用既有规则 | + +主体必填资料指:`fullName`、`taxNo`、`legalRepresentative`、`legalRepresentativeIdNo`、`legalRepresentativeIdCardFrontUrl`、`legalRepresentativeIdCardBackUrl`、`contactPhone`、`establishDate`、`balance`、`paymentType`、`mainCooperation`、`licenseImageUrl`、`address`。 + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| `data.supplierId` | String | 供应商 ID | +| `data.status` | String | 保存后的状态 | +| `data.initialAccounts` | Array | 当前初始账户摘要 | +| `data.updateTime` | String | 保存后的新并发版本 | + +#### 请求示例 + +```json +{ + "shortName": "示例供应商", + "expectedUpdateTime": "2026-09-04 16:48:49" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "success": true, + "data": { + "supplierId": "2095000000000000001", + "status": "DRAFT", + "initialAccounts": [{"accountId": "2095000000000000002", "status": "DRAFT"}], + "updateTime": "2026-09-04 16:49:16" + } +} +``` + +#### 空数据 / 降级响应 + +省略未修改字段会保留已存值;接口没有空数据成功或降级成功。 + +#### 错误响应 + +```json +{"code":400,"message":"供应商类型不能为空","data":null,"success":false} +``` + +#### 业务边界 + +- 写入仍要求 `FINANCE` 或 `SUPER_ADMIN` 及 `supplier:update` 权限。 +- 保存前按“请求值 + 已存值”校验完整聚合;存量资料缺项时,必须补齐后才能保存其他修改。 +- 非草稿账户继续走独立账户审批;本次不改变状态、并发、审批、幂等或审计规则。 +- `expectedUpdateTime` 过期返回既有业务码 `395014`,失败不更新任何聚合数据。 + +## 四、契约约束与正确调用方式(接口类必写) + +| 场景 | 正确调用 | +|---|---| +| 新建 | 一次提交全部主体必填资料、非空 `types`、非空 `contacts` 和一个 `initialAccounts` | +| 修改普通字段 | 先查询详情;已存聚合完整时,只提交变化字段和最新 `expectedUpdateTime` | +| 修改关系快照 | 提交完整非空快照;不修改关系时省略对应字段 | +| 字典字段 | 提交字典接口返回的 `dictValue`,不要提交中文标签或前端硬编码默认值 | + +支付类型当前字典值为 `1`(现付)、`2`(签单)、`3`(月付);供应商类型和联系人角色分别从 `supplier_type`、`sup_content_role` 动态字典读取。 + +## 五、数据库行为 + +- 校验失败不新增或更新供应商聚合数据。 +- 本次没有表结构、字段非空约束、数据迁移或历史数据回填。 + +## 六、边界行为 + +- 业务失败可能仍为 HTTP 200;前端必须检查 `success=false` 和业务 `code/message`。 +- 必填文本为空白、必填值为 `null`、必填集合为空时均拒绝。 +- 更新省略字段表示保留,不等于清空;完整性按保存后的有效聚合判断。 +- 超过列表上限、字典值失效、身份证/电话/URL 格式不合法时继续使用既有校验错误。 + +## 六.6、修改前后对比 + +| 行为 | 改前 | 改后 | +|---|---|---| +| 新建缺主体资料 | 部分字段可缺失并保存草稿 | 任一约定主体必填资料缺失即拒绝 | +| 新建缺关系资料 | 类型、联系人或账户可能为空 | 三类均必须非空 | +| 修改显式空关系快照 | 可清空部分关系 | `types: []`、`contacts: []`、`initialAccounts: []` 均拒绝 | +| 修改省略未变化字段 | 保留现值 | 仍保留现值,并校验最终聚合完整性 | + +## 六.7、影响评估 + +- **是否破坏向后兼容**: 是。依赖不完整草稿或显式清空类型、联系人、初始账户的旧请求会被拒绝。 +- **前端是否必须同步上线**: 是。新建和编辑表单均需补齐必填标识、校验提示和提交数据。 +- **前端 workaround 清理点**: 不再允许以空数组清空供应商类型、联系人或初始账户。 + +## 七、不影响范围 + +- 响应结构和字段名不变。 +- 不改变供应商注册提交接口、权限矩阵、状态机、审批流、并发版本、幂等与审计语义。 +- 不改变非草稿账户独立审批入口,也不修改数据库约束。 + +## 八、测试环境已验证 + +- 新建缺注册地址、联系人或账户分别返回业务码 `400`,且无业务数据写入;完整资料创建成功。 +- 修改显式空类型、联系人、账户或清空营业执照分别返回业务码 `400`,资料与版本不变;完整存量上的增量修改成功。 +- 匿名新建返回业务码 `401`;验收草稿已通过应用删除接口清理,有效聚合数据为零。 + +## 十、相关文档 + +- [后端 Issue #7087](https://git.1814.love:8443/wx/HL/issues/7087) +- [后端 PR #7093](https://git.1814.love:8443/wx/HL/pulls/7093) +- [历史契约 #6343](https://git.1814.love:8443/wx/HL/issues/6343):其中“新建可空类型、修改可显式清空类型”已被本工单取代。 + +## 关联 / 联系人 + +### 链接 + +- **Issue**: [#7087](https://git.1814.love:8443/wx/HL/issues/7087) +- **PR**: [#7093](https://git.1814.love:8443/wx/HL/pulls/7093) +- **Merge commit**: [e8b96e9a5](https://git.1814.love:8443/wx/HL/commit/e8b96e9a5dd0c75e65157bf889336ef740533da4) + +### 联系人 + +- **后端负责人**: @lc