@@ -0,0 +1,96 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "6258"
|
||||
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: "2026-08-24"
|
||||
status_note: "PR #6264 已合并 dev-v3,合并提交 5c27bee4f 已在 TEST Gateway 验证。供应商联系人请求和详情响应新增 isPrimary;服务端在聚合锁与本地事务内保证同一供应商至多一个默认联系人,并兼容旧请求省略字段。"
|
||||
updated_at: "2026-08-24"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 供应商联系人默认标识与唯一性逻辑
|
||||
|
||||
供应商注册和资料维护链路为联系人增加默认标识 `isPrimary`。字段为可空 Boolean;服务端根据创建、完整提交和增量更新的不同语义处理省略值,并保证一个供应商最多只有一个默认联系人。
|
||||
|
||||
## 变更接口
|
||||
|
||||
| 方法 | 路径 | 行为变化 |
|
||||
|---|---|---|
|
||||
| POST | `/admin/supplier/items/add` | 请求 `contacts[].isPrimary` 可选;省略按 `false` 保存;显式提交多个 `true` 时整次创建失败且零写入 |
|
||||
| PUT | `/admin/supplier/items/{supplierId}/update` | 已有联系人省略 `isPrimary` 时保持原值;新增联系人省略时按 `false`;显式将另一联系人设为 `true` 时在同一事务内清除原默认联系人 |
|
||||
| POST | `/admin/supplier/items/{supplierId}/submit` | 完整联系人快照支持 `isPrimary`;省略按 `false`;显式提交多个 `true` 时在主体、联系人、审计和审批写入前失败 |
|
||||
| GET | `/admin/supplier/items/{supplierId}/basic-info/view` | 响应 `contacts[]` 新增 Boolean 字段 `isPrimary`;联系电话仍只返回脱敏字段 `contactPhoneMask` |
|
||||
|
||||
请求和响应示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"contacts": [
|
||||
{
|
||||
"contactId": "1234567890123456789",
|
||||
"contactName": "联系人甲",
|
||||
"contactPhone": "13800000000",
|
||||
"contactRole": "BIZ",
|
||||
"isPrimary": true,
|
||||
"expectedUpdateTime": "2026-08-24 17:30:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`Long` 类型的 `contactId` 继续按字符串传输,时间格式保持 `yyyy-MM-dd HH:mm:ss`。
|
||||
|
||||
## 字段语义与兼容性
|
||||
|
||||
- 创建草稿和完整提交:`isPrimary=true` 表示默认联系人;`false`、`null` 或省略均按非默认联系人处理。
|
||||
- 增量更新已有联系人:省略 `isPrimary` 表示不修改该联系人当前默认状态;显式 `false` 表示取消默认。
|
||||
- 增量更新新增联系人:省略 `isPrimary` 按 `false` 保存。
|
||||
- 显式设置新的默认联系人时,服务端锁定当前联系人集合,在同一聚合事务内清除原默认联系人并设置新值。
|
||||
- 允许没有默认联系人;取消或删除默认联系人后不会自动选举其他联系人。
|
||||
- 旧客户端不传 `isPrimary` 时,创建、更新和提交请求保持兼容。
|
||||
- 不新增或修改数据库 migration;复用既有 `supplier_contact.is_primary` 列。
|
||||
|
||||
## 校验与错误语义
|
||||
|
||||
- 单次请求显式包含两个及以上 `isPrimary=true` 时返回业务码 `400`,消息为 `同一供应商只能设置一个默认联系人`。
|
||||
- 重复默认校验在业务写入前执行;失败请求不会修改供应商版本、联系人、审计记录或审批状态。
|
||||
- 写权限保持不变:`FINANCE` 和 `SUPER_ADMIN` 可写,`ADMIN` 返回业务码 `395002`、消息 `无权执行该供应商写操作`。
|
||||
- 业务失败可能仍使用 HTTP 200,客户端必须同时检查统一响应的 `code`、`success`、`message` 和 `data`。
|
||||
|
||||
## 未变化范围
|
||||
|
||||
- 不新增接口、Gateway 路由、菜单权限、角色、状态机或审批节点。
|
||||
- 不改变联系人电话加密存储、脱敏输出、软删除、审计、聚合锁、幂等与乐观版本语义。
|
||||
- 不修改配置、Redis Key 或 MQ 契约。
|
||||
- 本工单仅交付后端;管理端需按本记录接入 `isPrimary` 字段和默认联系人交互。
|
||||
|
||||
## 验证证据
|
||||
|
||||
- 自动化:定向 37 项零失败;Resource 全量 1941 项零失败、38 项仓库既有条件跳过;Gateway 8 项零失败;合并后独立审计再跑权限、事务和契约相关 55 项零失败。
|
||||
- TEST Gateway:35 个真实认证断言通过,覆盖创建单默认、切换默认、旧请求省略字段、显式取消后零默认、创建/更新/提交多个默认失败且零写入、电话脱敏和 ADMIN 越权拒绝。
|
||||
- TEST 数据库:两个有效联系人切换后统计为 `2:1`,显式取消后统计为 `2:0`。
|
||||
- 部署证明:当前远端 `dev-v3` 包含合并提交 `5c27bee4f`,TEST Gateway 已实际回显并执行新增 `isPrimary` 行为。
|
||||
- 清理:所有合成供应商草稿均已软删除,按测试前缀查询有效数据为 0;测试账号当前角色已恢复为 `SUPER_ADMIN`,此前登录失败计数已通过管理接口清理。
|
||||
|
||||
## 撤回
|
||||
|
||||
1. 从最新 `dev-v3` 创建回退分支,执行 `git revert -m 1 --no-edit 5c27bee4f5d76d85c9c58727c05b330bc06ab608`,经独立 PR 合入。
|
||||
2. 重新构建并滚动部署 `hl-resource-service`;不执行 DDL 或 DML,不恢复配置、Redis 或 MQ。
|
||||
3. 回退代码会忽略既有 `supplier_contact.is_primary` 值;旧请求继续兼容,依赖新字段的管理端应同步停止使用 `isPrimary`。
|
||||
4. 经 Gateway 复测创建、更新、提交和详情四个既有接口,并确认联系人电话仍脱敏、草稿删除与权限门禁正常。
|
||||
|
||||
## 关联 / 联系人
|
||||
|
||||
- **Issue**: [#6258](https://git.1814.love:8443/wx/HL/issues/6258)
|
||||
- **PR**: [#6264](https://git.1814.love:8443/wx/HL/pulls/6264)
|
||||
- **合并提交**: [5c27bee4f](https://git.1814.love:8443/wx/HL/commit/5c27bee4f5d76d85c9c58727c05b330bc06ab608)
|
||||
- **后端负责人**: @lc
|
||||
在新工单中引用
屏蔽一个用户