# 07 — ref_count 引用计数全量接线(业务三模块) **Type:** task (HITL) **Status:** resolved (20260907) **Blocked by:** 03 ## What to build 拍板 1:把 `DictReferenceService`(increment/decrement/batchApply,均 @Transactional)接进业务写路径,**与业务写入同一事务**。约 8-10 处写点: 1. **crm-lead**:新增/编辑保存与清除 `lead_source`、`brand`、`product`、`scene` 字典编码处,旧值 decrement、新值 increment;线索导入 executor 走 `batchApply`(应用层聚合 delta,禁循环逐条——ADR-0015 热点对策)。 2. **crm-opportunity**:OpportunityIntake(建档)、销售直接新建、编辑——`opp_source`、`industry` 两字段同上。 3. **crm-customer**:新增/编辑——`customer_type`、`industry`;客户导入走 `batchApply`。 4. **getNames 回显悬空容错**:管理员 force-delete(兵底)仍可造出悬空编码——名称缺失时降级(返回编码原样或空串,实现票内定并写进 CONTEXT.md「名称回显」词条)。 **验收**:每模块接线点集成测试(保存/清除/换值/批量导入的计数断言);计数增减与业务写入同事务回滚验证(抛异常后计数不变);既有三模块测试回归全绿。 ## Answer 全部落地(20260907)。四模块测试全绿:crm-dict **55/55**、crm-lead **131/131**、crm-opportunity **262/262**、crm-customer **186/186**(含上游 rule/preference 回归)。 **缝设计(crm-dict 侧,一处机制)**: - `DictReferenceService.applyFieldChange(group, oldCode, newCode)` 字段级随迁:相等不动、**空白串归一 null**(表单"清空"常以空串到达)、旧减新加;新建传 null、清除传 null。 - `getNames` 悬空兜底:未命中编码回显**编码本身**(force-delete 后历史数据不出现空名称);CONTEXT.md「名称回显」「引用计数」两词条已同步。 **接线点(业务侧,全部与业务写入同事务)**: | 模块 | 写点 | 字段(分组) | |---|---|---| | crm-lead | `createLead`(save 后入账)/ `editLead`(updateById 后,null=未传不动守卫) | channelCode(lead_source)、brandCode(brand)、productCode(product)、sceneCode(scene) | | crm-opportunity | `OpportunityIntakeImpl.open`(建档入账,覆盖线索转入+直接新建两入口)/ `OpportunityDetailServiceImpl.edit`——**EDIT_FIELDS record 加 `dictGroup` 分量**,引用计数与 SET 子句、字段审计同一字段表同源(加字段只动一处) | oppSource(opp_source)、industryCode(industry) | | crm-customer | `CustomerServiceImpl.create/update`(全量覆盖语义:拷贝前抓旧值,CAS 成功后随迁)/ `CustomerImportExecutor`(行级聚合 delta,客户 sheet 收尾一次 `batchApply`——ADR-0015 热点对策) | customerType(customer_type)、industryCode+industryChildCode(industry) | | 常量 | OpportunityConstants/CustomerConstants 补 `DICT_GROUP_*` 常量(customer detail 原字面量一并换常量) | — | **测试说明(验收项的如实偏差)**:计数级断言落在 crm-dict 的 H2 集成测试(`DictReferenceServiceTest` 新增 2 例:新建/换值/清除/相等不动 + 空白归一);三业务模块测试为 Mockito 单测(H2 基建无 dict 表),接线点以 mock 注入回归 + 既有用例全绿兜底,未在业务侧做计数断言。"同事务回滚"由业务方法既有 `@Transactional` + `DictReferenceServiceImpl` REQUIRED 传播结构保证,未单独做回滚断言。 **过程中的顺带修复**:`OpportunityIntakeImplTest` 缺新依赖 mock 导致 12 个 NPE(补 `@Mock DictReferenceService` 后全绿);客户模块直跑报 `CustomerReminderRuleDTO` NoClassDefFound 系本地仓库 crm-rule 构件过期(与本次无关,`-am` 源码构建即解)。