You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
34 lines
2.5 KiB
34 lines
2.5 KiB
|
3 weeks ago
|
# 12 商机侧新增入口:关联线索校验
|
||
|
|
|
||
|
|
Type: task
|
||
|
|
Status: open
|
||
|
|
Blocked by: 03
|
||
|
|
|
||
|
|
## Question
|
||
|
|
|
||
|
|
产品明确:商机侧新增商机入口(A3-1-1-2-1,票 03 定的直接创建入口),当用户选**商机来源 =「线索转入」** 时,需要在表单里选一条【关联线索】。
|
||
|
|
|
||
|
|
本票落地这个交互 + 服务端校验规则。**不改主表字段**——【关联线索】复用票 02 已建的 `source_lead_id`,只是把这个字段从"仅线索侧 port 能写"扩展到"商机侧新增表单也能写"。
|
||
|
|
|
||
|
|
## 决策(已定,落实现)
|
||
|
|
|
||
|
|
- **字段**:复用 `source_lead_id`(票 02,商机主表已建)。**不新建** `related_lead_id`。
|
||
|
|
- **唯一性**:靠已有 `UNIQUE(source_lead_id)`(票 02),一条线索只能关联一条商机——同一条 DB 约束覆盖两条入口。
|
||
|
|
- **必填触发**:仅在**商机侧新增入口**、用户选 `oppSource == "线索转入"` 时,`source_lead_id` 必填。线索侧 port 走的路径 `oppSource` 由商机侧入口层自动填、`source_lead_id` 从 cmd 带,不走此校验(票 02)。
|
||
|
|
- **候选范围**:可关联的线索状态 = **已领取(3) / 跟进中(4)**(对齐 `crm-lead/service/impl/LeadServiceImpl` 中"仅已领取/跟进中线索可转商机"的准入条件,两条入口对称)。
|
||
|
|
- **唯一性预检**:新增提交前查一次 `source_lead_id` 是否已被占用;命中则返回业务错误"该线索已关联其他商机",避免依赖 DB 唯一键冲突走错误路径。DB 唯一键仍作最终防线(并发下捕获 → 报错,不做静默返回——这里是商机侧新建,不是 port 的幂等场景)。
|
||
|
|
|
||
|
|
## 落地清单
|
||
|
|
|
||
|
|
1. 商机侧新增商机 API(DTO/Controller/Service):
|
||
|
|
- 表单新增【关联线索】下拉字段(前端),后端 DTO 加 `sourceLeadId`(Long,可空)。
|
||
|
|
- 校验规则:`oppSource == "线索转入"` → `sourceLeadId` 必填;否则可空。
|
||
|
|
- 候选下拉的服务端接口:查询 `owner_user_id = 当前用户`(或按 DataScope 可见) **AND** `status IN (3, 4)` **AND** `source_lead_id` 未被任何商机占用 的线索。
|
||
|
|
2. 命中已占用时:`{code: "opp.related_lead.taken", message: "该线索已关联其他商机"}` 之类的明确错误码。
|
||
|
|
3. 两条入口共用建商机核心逻辑(票 02 定)不变:核心逻辑不关心 `source_lead_id` 从哪来,只负责 insert + 幂等;候选/校验/联动在入口层做。
|
||
|
|
|
||
|
|
## ⚠ 依赖
|
||
|
|
|
||
|
|
- 依赖票 03(主表结构,已 resolved)。
|
||
|
|
- 不阻塞其他票;实现顺序放到主表 + 状态机(票 04)落地之后。
|