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.
32 lines
3.7 KiB
32 lines
3.7 KiB
|
2 days ago
|
# 03 商机侧硬依赖契约
|
||
|
|
|
||
|
|
Type: research
|
||
|
|
Status: resolved
|
||
|
|
Blocked by: —
|
||
|
|
|
||
|
|
## Question
|
||
|
|
|
||
|
|
crm-customer 对 crm-opportunity 的硬依赖全景,供 Demo「关联商机」相关呈现:
|
||
|
|
|
||
|
|
1. 客户详情「关联商机」页签:走哪个端点(crm-opportunity 侧 list-by-customer?)、出参字段(brief 提到 G2「关联商机 7 vs 13 列」契约漂移——以实现实际返回为准列出列清单)。
|
||
|
|
2. 新增/编辑客户挂商机:opp_id 可空化(backend 票 ticket01)后的字段语义与端点行为。
|
||
|
|
3. 客户归属变更(换负责人/抛公海/归档/交割)对名下商机的影响:哪些动作会级联商机状态,Demo 流程闭环演示需要覆盖哪些级联现象。
|
||
|
|
4. 商机创建是否依赖客户存在(商机侧硬依赖的反向):Demo 是否需要演示「从客户发起建商机」。
|
||
|
|
|
||
|
|
产出:依赖清单(端点×字段×触发场景),落在 Answer 内(量小)或 `assets/opp-deps.md`。
|
||
|
|
|
||
|
|
## Pointers
|
||
|
|
|
||
|
|
- `crm-opportunity` 模块 Controller;`crm-customer` 详情页签实现(CustomerDetailController)。
|
||
|
|
- gap-report G2(7 vs 13 列)原文:`.scratch/customer-frontend-handover/gap-report.md`。
|
||
|
|
- 现有 demo「关联商机」页签实现(`.scratch/customer-e2e/demo/index.html` 搜「关联商机」)。
|
||
|
|
|
||
|
|
## Answer
|
||
|
|
|
||
|
|
详细依赖清单(端点×字段×触发场景 + SQL + 源码定位):`assets/opp-deps.md`。要点:
|
||
|
|
|
||
|
|
1. **关联商机页签**:`GET /api/customer/opportunity/page?id=`(CustomerDetailController)→ 出站 port `CustomerOpportunityQueryPort`,crm-opportunity `CustomerOpportunityQueryPortImpl`(@Primary)承接;SQL = `opportunity_customer` join `opportunity`(delete_key=0),更新倒序。**出参恒 7 字段**:id / oppName / stageName(crm-rule describeStages 批量解析当前节点展示名)/ estimateAmount(=project_amount)/ ownerUserId / ownerNameSnapshot / updateTime。G2 的 13 列是原型期望,缺列挂账跨模块票(issues-07 §C 已收窄);Demo 契约事实=7 字段,缺列显「--」。旧 demo 3 处字段名漂移(opportunityName/ownerUserName/statusName 均不命中,回退显 id 或「--」)——新 demo 按真名渲染。
|
||
|
|
2. **「新增/编辑客户挂商机」前提修正**:Customer 实体与 Create/UpdateDTO 零商机字段,customer 侧无挂商机关联口;关联唯一真源=商机侧 `opportunity_customer` 子表。ticket01 的 `opp_id` 可空化是 `opportunity_scheme_card.opp_id`(方案卡遗留列,ADR-0041;迁移器仅在列仍 NOT NULL 时 ALTER,幂等),与客户域无关。Demo 不做该表单。
|
||
|
|
3. **归属变更级联矩阵**:claim/releasePool **前置阻断**(hasActiveOpportunity:opp_status IN 1,2,3 计数>0;claim→67007、抛公海→67007、归档→67006;批量归档先整批预检);**assign 换负责人不级联**(客户/商机负责人可漂移——不对称点,值得 demo 呈现);交割两段**强级联**:initiate 整批原子(客户+商机+项目 owner 同刷接收总监,任一失败全回滚)、assignOne 逐条独立事务,商机侧刷 owner 三列(owner_dept_id=DataScope 锚点跟人走),不 bump 乐观锁、**不写商机 oplog**(项目侧才逐项目写 TRANSFER 动态,c9d6e75)。商机终结态 4/5 不阻断抛公海/归档。
|
||
|
|
4. **反向依赖=弱**:`POST /api/opportunity` customerId 可空(非空时 isPrimaryIntended+customerRole 必填);直接新建路径不做客户存在性校验,商机详情 `POST /api/opportunity/customer/add` 才走 requireLive(不存在/已归档拒)。归档客户存量关联行不清理(页签仍反查得到),但商机详情侧不可再新挂。客户侧无「从客户建商机」端点——Demo 用 `POST /api/opportunity` 预填 customerId 合成该入口即可,无需新后端。
|