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.
66 lines
4.5 KiB
66 lines
4.5 KiB
|
2 weeks ago
|
# 13 商机-客户关联子表(关联客户 + 主要意向客户)
|
||
|
|
|
||
|
|
Type: spec
|
||
|
|
Status: resolved
|
||
|
|
Related: 03, 07, 10, 11
|
||
|
|
|
||
|
|
## 背景
|
||
|
|
|
||
|
|
原型确认:一个商机维护**多个关联客户**,其中恰好一个标记为**主要意向客户**。产品口径拍板(本票):
|
||
|
|
|
||
|
|
- 线索转商机时填的「意向客户」→ 落为该商机的**主要意向客户**(`is_primary_intended=1`)。
|
||
|
|
- 商机侧可**添加普通关联客户**(`is_primary_intended=0`)。
|
||
|
|
- 可**修改主要意向客户**(切换标记,事务内旧主→0 新主→1)。
|
||
|
|
- **商机有且只有一个主要意向客户**。
|
||
|
|
|
||
|
|
原型证据(概览页 A3-1-1-1-1 / 客户信息页 A3-1-1-1-2,存档 research-a31111-detail-overview.md):
|
||
|
|
- line 546/763:「主要意向客户」字段;line 769「同一商机原则上仅展示一个主要意向客户」。
|
||
|
|
- line 1235「取关系标记为『主要意向客户』的关联客户」。
|
||
|
|
- line 1269-1275「其他关联客户」= 除甲方和主要意向客户以外的关联客户,多条动态展示。
|
||
|
|
- line 1334 客户角色示例:机电总包/工程商/集成商 → crm-dict 字典。
|
||
|
|
- line 786「每张方案卡需关联当前商机下的一个客户」+ 810「不允许无客户归属的孤立方案卡」。
|
||
|
|
|
||
|
|
之前票 03 line 87-94 把该子表记为「另议/挂 A4 依赖」、map.md 列在 Not yet specified;本票将其钉死并成实体。
|
||
|
|
|
||
|
|
## 决策
|
||
|
|
|
||
|
|
### 实体 `opportunity_customer`(住 `crm-opportunity`)
|
||
|
|
|
||
|
|
| 字段 | 类型 | 必填 | 说明 |
|
||
|
|
|---|---|---|---|
|
||
|
|
| `id` | bigint PK | ✅ | |
|
||
|
|
| `opportunity_id` | bigint | ✅ | 所属商机(外键语义,不建物理 FK 视仓库约定) |
|
||
|
|
| `customer_id` | bigint | ✅ | 引用 A4 客户模块(未建)→ 先存 id + 名快照,同票 11 走法(引用+快照并存) |
|
||
|
|
| `customer_name_snapshot` | varchar(200) | ✅ | 客户名快照,免 join,列表/详情高频展示 |
|
||
|
|
| `customer_role` | varchar(32) | 条件 | 客户角色(机电总包/工程商/集成商…)→ crm-dict 新增「客户角色」分组 |
|
||
|
|
| `is_primary_intended` | tinyint 0/1 | ✅ | **是否主要意向客户**;一商机唯一 =1 |
|
||
|
|
| `create_time`/`create_user_id` | | ✅ | 审计 |
|
||
|
|
|
||
|
|
### 约束
|
||
|
|
|
||
|
|
1. **主要意向客户唯一**:一商机 `is_primary_intended=1` 至多一条(应用层事务保证;DB 可用「部分唯一索引 `UNIQUE(opportunity_id) WHERE is_primary_intended=1`」或等价手段,视 MySQL 版本,落地时定)。
|
||
|
|
2. **一客户在一商机下只关联一次**:`UNIQUE(opportunity_id, customer_id)`。
|
||
|
|
3. **无孤立**:关联客户必属某商机;删商机级联清理(软删口径随商机)。
|
||
|
|
|
||
|
|
### 入口 / 交互
|
||
|
|
|
||
|
|
- **线索转商机**(票 11 实现):`cmd.customerId()` → 建一条 `is_primary_intended=1` 主要意向客户。
|
||
|
|
- **商机侧添加关联客户**(A3-1-1-2-4):建 `is_primary_intended=0` 普通关联客户。
|
||
|
|
- **修改主要意向客户**:事务内把原 `=1` 置 0、目标置 1;始终保持恰好一条主客户。
|
||
|
|
- 客户信息 Tab(A3-1-1-1-2):主要意向客户 + 其他关联客户分区展示(原型 line 1269)。
|
||
|
|
|
||
|
|
### 与主表 / 方案卡 / 列表联动
|
||
|
|
|
||
|
|
- **主表冗余**(票 03 C3):`primary_customer_id` + `primary_customer_name_snapshot` 冗余进商机主表(= 主要意向客户 id/名),高频展示免 join;切换主客户时同步刷新主表冗余。
|
||
|
|
- **方案卡(票 07)一客户一卡**:方案卡表加 `UNIQUE(opportunity_id, customer_id)`(Q2 产品确认)。每张方案卡必挂一个当前商机下的关联客户(无孤立卡)。
|
||
|
|
- **列表派生列(票 10 / P0-4)**:
|
||
|
|
- **方案预算列** = 主要意向客户那张方案卡的 `scheme_budget`(无卡则空)。
|
||
|
|
- **方案卡状态列** = 主要意向客户那张方案卡的 `card_status`(无主客户卡 → 未创建)。
|
||
|
|
- **不引入 `is_primary`(主卡)**:主键是客户不是卡;取值锚点 = 主要意向客户(`is_primary_intended`)。
|
||
|
|
|
||
|
|
## 依赖 / 遗留
|
||
|
|
|
||
|
|
- **A4 客户模块(未建)**:`customer_id` 引用真实客户实体、"添加关联客户"下拉数据源均依赖 A4。A4 到达前,本子表可建(引用 id + 名快照走法),但下拉选客户能力挂 A4(同票 11)。
|
||
|
|
- crm-dict 新增「客户角色」分组(机电总包/工程商/集成商…原型示例,实际选项集待产品)。
|
||
|
|
- ⚠ 遗留(不阻塞建模):客户联系人是否本子表冗余,还是随 A4 客户/联系人查(原型客户信息页展示联系人/职务/电话)——挂 A4 边界,A4 前沿到达再钉。
|