Browse Source
票15 全局默认阶段模板兜底 seed 已实现落地;票16 转商机同步事务补齐 (阶段落位+初始日志+团队成员)blocked by 15 现已解除,待开工。master
3 changed files with 123 additions and 2 deletions
@ -0,0 +1,53 @@ |
|||
# 15 全局默认阶段模板兜底 seed(crm-rule) |
|||
|
|||
Type: task |
|||
Status: resolved |
|||
Blocked by: 06 |
|||
|
|||
## Question |
|||
|
|||
系统需预置一条**发布中的全局默认阶段模板**,作转商机时 `resolveBindingVersion` 的命中兜底。 |
|||
产品拍板(20260826)默认阶段轨道:**客户圈定 → 关系摸排 → 资料采集 → 方案卡 → 已转项目**。 |
|||
|
|||
这不是新发明——**方案卡模板已有此范式**(`SchemeFieldDefInitializer` §2「兜底模板种子化」,grill 拍板 20260821:植入一条全公司通用发布中默认模板作建卡兜底)。 |
|||
阶段模板漏了对称的这一条,本票补齐。 |
|||
|
|||
## 已核实事实(本票零 A4 依赖、零字典改动) |
|||
|
|||
- **`opp_stage` 字典 5 项已种好**(`crm-dict/DictDataInitializer`,code 完全对上): |
|||
`OPP_STAGE_01 客户圈定` / `02 关系摸排` / `03 资料采集` / `04 方案卡` / `05 已转项目`。 |
|||
→ 本票**不碰字典**,只把这 5 项组装成一个 V-CONFIG 模板版本行。 |
|||
- **范式模板** = `crm-rule/config/SchemeFieldDefInitializer`(`CommandLineRunner` + `@Order` + 按 code 幂等判存,含已停用不复活)。 |
|||
- **实体**:`OpportunityStageTemplate`(头:`template_code`/`template_name`/`version_no`/`status`/`apply_scope`/`is_default`/`template_desc`) |
|||
+ `OpportunityStageNode`(节点:`template_id`/`seq_no`/`stage_dict_code`/`custom_node_name`/`work_goal`/`is_fixed`)。 |
|||
- **常量**(`OpportunityRuleConstants`)已有:`STAGE_TPL_CODE_PREFIX="OPP_STAGE_TPL_"` / `FIXED_STAGE_DICT_CODE="OPP_STAGE_05"` / `FIXED_STAGE_NAME="已转项目"` |
|||
/ `VERSION_STATUS_PUBLISHED=2` / `APPLY_SCOPE_ALL=1` / `FLAG_YES=1`。 |
|||
**缺** `SEED_STAGE_TPL_CODE` / `SEED_STAGE_TPL_NAME`(对称方案卡的 `SEED_SCHEME_TPL_CODE/NAME`)。 |
|||
- **消费缝**:`IOpportunityStageTemplateService.resolveBindingVersion(deptId)` javadoc 明写「无任何发布中模板可匹配时返回 null」——seed 保证常态命中,票 16 的「容忍空」退化为极端兜底(管理员停用全部模板才触发)。 |
|||
|
|||
## 实现范围 |
|||
|
|||
1. **常量**:`OpportunityRuleConstants` 加 `SEED_STAGE_TPL_CODE = STAGE_TPL_CODE_PREFIX + "01"`(= `OPP_STAGE_TPL_01`)+ `SEED_STAGE_TPL_NAME`(如「全公司通用阶段模板」)。 |
|||
2. **`StageTemplateInitializer`**(`crm-rule/config`,照 `SchemeFieldDefInitializer` 范式): |
|||
- `CommandLineRunner`,`@Order` 排在阶段模板依赖就绪之后。 |
|||
- 幂等键 = `template_code`:同 code 行存在(含已停用)即跳过,管理员停用后重启不复活。 |
|||
- 首装植入: |
|||
- **1 头**:`template_code=SEED_STAGE_TPL_CODE`、`version_no="V1.0"`、`status=发布中`、`apply_scope=所有商机`、`is_default=1`、`template_name=SEED_STAGE_TPL_NAME`、`template_desc` 说明系统初始化兜底。 |
|||
- **5 节点**(`template_id=` 回填的头 id,`seq_no` 1-5): |
|||
| seq | stage_dict_code | is_fixed | |
|||
|---|---|---| |
|||
| 1 | OPP_STAGE_01(客户圈定) | 0 | |
|||
| 2 | OPP_STAGE_02(关系摸排) | 0 | |
|||
| 3 | OPP_STAGE_03(资料采集) | 0 | |
|||
| 4 | OPP_STAGE_04(方案卡) | 0 | |
|||
| 5 | OPP_STAGE_05(已转项目) | **1**(固定末节点,票 06 契约)| |
|||
- `custom_node_name` 留空(带入字典名),`work_goal` 留空。 |
|||
3. **测试** `StageTemplateInitializerTest`(照 `SchemeFieldDefInitializerTest` 范式,Mockito + `TableInfoHelper.initTableInfo`): |
|||
- 首装:种 1 头(发布中/全公司通用/默认/V1.0/固定编码)+ 5 节点(seq 1-5、末节点 `is_fixed=1` 且 `stage_dict_code=OPP_STAGE_05`、前 4 节点 `is_fixed=0`)。 |
|||
- 幂等重跑:模板按 code 判存(含已停用),插入总数不变(1 头 5 节点各补 0)。 |
|||
|
|||
## 边界 |
|||
|
|||
- **不碰 `opp_stage` 字典**(已种)。 |
|||
- **不改 `resolveBindingVersion` 服务逻辑**(已实现,本票只喂它数据)。 |
|||
- 不做「指定部门」范围模板(`apply_scope=2`);本票只种「所有商机」默认兜底一条。 |
|||
@ -0,0 +1,60 @@ |
|||
# 16 票 02 转商机同步事务补齐:阶段落位 + 初始操作日志 + 团队成员 |
|||
|
|||
Type: task |
|||
Status: open |
|||
Blocked by: 15 |
|||
|
|||
## Question |
|||
|
|||
票 02 底稿「簇 D — 事务边界 + 转商机时的子表」要求转商机时**同步事务内**做 5 件事, |
|||
`OpportunityCreationPortImpl` 现只落了其中 3 项(幂等检查、建主表、建关联客户),**缺 3 步**: |
|||
|
|||
| 步 | 底稿要求(票 02 簇 D) | 现状 | |
|||
|---|---|---| |
|||
| 1 | 幂等检查(查 source_lead_id) | ✅ 已落(票 12 预检 + DB uk 兜底)| |
|||
| 2 | 建商机主表行 + **初始状态/阶段** | ⚠️ 主表 ✅,**阶段落位缺**(`current_stage_id` 未设)| |
|||
| 3 | 写一条初始操作日志(「由线索转入创建」)| ❌ **缺** | |
|||
| 4 | 建团队成员一条(领取人=商机负责人)| ❌ **缺** | |
|||
| 5 | 建关联客户一条(主要意向客户)| ✅ 已落(customerId 非空时)| |
|||
|
|||
本票补齐第 2(半)/3/4 步。**三步全是商机域内部写入,零 A4 依赖。** |
|||
|
|||
## 决策(20260826 拍板) |
|||
|
|||
- **阶段落位「无发布中模板」= 容忍空(走法 A)**:`resolveBindingVersion` 返 null 时 `current_stage_id=null`,商机照建,不阻塞转商机。 |
|||
票 15 已预置全局默认阶段模板,常态必命中,「容忍空」退化为极端兜底(管理员停用全部模板才触发)。 |
|||
与模块「customerId 可空占位、不倒退」哲学一致。 |
|||
|
|||
## 已核实事实(基础设施齐备) |
|||
|
|||
- **阶段落位缝**:`IOpportunityStageTemplateService.resolveBindingVersion(deptId)` → 命中取版本行 |
|||
→ `listNodesOfVersion(versionId)` 取 `seq_no` 首节点。写法可抄 `OpportunityConvertPortImpl`(转项目端口已用同款缝驱动 `current_stage_id`)。 |
|||
- **操作日志**:`OpportunityOplog` + `OpportunityOplogMapper`;枚举 `OplogKind.ROW_ADD` / `OplogLogType.ROW_CHANGE` / `opSource="SYSTEM"`。 |
|||
- **团队成员**:`OpportunityTeam` + `OpportunityTeamMapper`(实体 javadoc 已点名「转商机时自动插一条:领取人=商机负责人(票 02)」); |
|||
`TeamMemberPermission.READ_WRITE`;`project_role_01`(crm-dict `project_role` 分组「商机负责人」,已核实)。 |
|||
- **主表阶段字段**(票 03/06):`current_stage_id`(节点 id)+ `stage_template_id`(版本行 id 锁版本)+ `stage_template_version`(varchar 冗余版本号)。 |
|||
|
|||
## 实现范围(`crm-opportunity/OpportunityCreationPortImpl`) |
|||
|
|||
1. **注入** `IOpportunityStageTemplateService` + `OpportunityOplogMapper` + `OpportunityTeamMapper`。 |
|||
2. **阶段落位**(第 2 步补齐,插主表前): |
|||
- `resolveBindingVersion(cmd.ownerDeptId())` → 命中:`stage_template_id=版本行 id`、`stage_template_version=版本号`、 |
|||
`current_stage_id=listNodesOfVersion 首节点 id`。 |
|||
- 返 null:三字段留空(容忍空,走法 A)。 |
|||
3. **初始操作日志**(第 3 步,插主表后):`opp_id=新id`、`opKind=ROW_ADD`、`logType=ROW_CHANGE`、 |
|||
`entityName="商机"`、`opDesc="由线索转入创建"`、`opSource="SYSTEM"`、`opTime=now`、`opUserId=cmd.ownerUserId()`。 |
|||
4. **团队成员**(第 4 步,插主表后):`opportunity_id=新id`、`userId=cmd.ownerUserId()`、 |
|||
`projectRole="project_role_01"`、`permission=READ_WRITE`、`deleteKey=0`、`userNameSnapshot` 从 cmd 若有(否则留空,A4/auth 侧补)。 |
|||
5. **单测**扩 `OpportunityCreationPortImplTest`(Mockito): |
|||
- 命中模板 → 断言 `current_stage_id`/`stage_template_id`/`version` 落位为首节点/版本行。 |
|||
- **无模板(resolveBindingVersion 返 null)→ 三字段空,商机仍建成功**(容忍空用例)。 |
|||
- 断言写了 1 条初始 oplog(ROW_ADD/ROW_CHANGE/SYSTEM/「由线索转入创建」)。 |
|||
- 断言插了 1 条团队成员(owner/project_role_01/READ_WRITE)。 |
|||
- 现有幂等/客户子表/并发用例保持绿。 |
|||
|
|||
## 边界 |
|||
|
|||
- **事务内 vs 异步**:本 3 步全属票 02 簇 D「必须同步」清单,与主表同事务;通知/推送仍异步(不在本票)。 |
|||
- **不改状态/阶段快照表**:`opportunity_status_history`/`opportunity_stage_history` 的初始快照是否要写, |
|||
票 02 簇 D 未列(只列 oplog)——本票**不写快照**,与簇 D 对齐;若后续需初始快照另开票。 |
|||
- 不动 A4:`userNameSnapshot` 缺失容忍(auth/A4 侧回填),不为此建跨模块查询。 |
|||
Loading…
Reference in new issue