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.
13 KiB
13 KiB
票 01 — 缺陷修复白盒验收核对清单(23 条)
effort: opportunity-acceptance · ticket: 01 · date: 20260831 · mode: 静态白盒(不起服)
结论
- 23/23 条修复锚点全部在位,0 条 ❌(opportunity-fix D-01 ×1 + bugfix D-01~D-22 ×22,其中 D-08/18/19 为翻案关闭项,核对「非缺陷形态保持」)。
- 次要瑕疵 3 处(均不阻塞验收,见 §C):D-01 方法 javadoc 残留旧方案描述 ×2、
OpportunitySubController重复 import ×1、错误码 64018 两族同值冲突(既有债务)。 - 全量单测结果见 §D(mvn-test.log)。
A. opportunity-fix D-01(重点:新建商机 500 根因修复)
| # | 核对点 | 锚点(文件#行为) | 代码现状 | 结论 |
|---|---|---|---|---|
| A1 | fail-fast 无零值兜底 | OpportunityIntakeImpl#applyInitialStage L135-152 |
resolveBindingVersion 返 null → 抛 OpportunityIntakeException(「系统未配置发布中的商机阶段模板…」);listNodesOfVersion 空 → 同抛;stage 三列(stage_template_id/stage_template_version/current_stage_id)仅在命中后赋值,无任何 =0 占位残留 |
✅ |
| A2 | 60001 友好错翻译链 | OpportunityCreateServiceImpl L94-98(DIRECT→BusinessErrorException(msg)→ResultCodeEnum.BUSINESS_ERROR=60001);OpportunityCreationPortImpl L59-63(LEAD_CONVERT→OpportunityCreationException) |
两条 seam 均在位,HTTP 层不再 500 | ✅ |
| A3 | 预设模板不可删/不可停(64018) | OpportunityRuleConstants L59/L99(SEED_STAGE_TPL_CODE="OPP_STAGE_TPL_01" / CODE_STAGE_TPL_SEED_PROTECTED=64018);OpportunityStageTemplateServiceImpl#disableTemplate L338-341 / #deleteDraft L354-357 |
两入口均按 templateCode 拦截(预设模板任何版本不可删/停,非仅发布中版),错误码/文案在位 |
✅ |
| A4 | publish 不破坏不变式 | OpportunityStageTemplateServiceImpl#publish L302-329 |
旧版顶替/默认顶替均直调私有 updateStatus,不走 disableTemplate → 编辑发布中预设模板生成新草稿再发布顶替不受保护拦截;「始终有一个发布中默认模板」不变式保持 |
✅ |
| A5 | current_stage_id 赋值链 | buildOpportunity L120 → applyInitialStage L149-151 |
stageTemplateId/stageTemplateVersion/currentStageId(首节点) 三列完整落位;buildOpportunity L96-103 的空串/0 兜底仅覆盖 oppType/bidForm/localityType/partyAClear/provinceCode/cityCode/industryCode(线索转入路径防御),与 D-01 stage 三列无关,非兜底残留 |
✅ |
| A6 | ⚠ 文档残留 ×2 | applyInitialStage javadoc L128-133 仍描述已撤销的「显式回填零值占位」旧方案;buildOpportunity L119 行注释「无模板容忍空,走法 A」同样过时 |
方法体已是 fail-fast(策略 B),注释与方法体矛盾,会误导后续维护;建议票 03(Demo 修正 session)顺手修正 | ⚠ 记录 |
B. opportunity-bugfix D-01~D-22 静态复核
裁决基线 = 票 02 retest-verdicts.md(19 确认 + 3 翻案);运行时终版 = 票 09(✅146/⚠2/❌0)。本表核对代码锚点在位。
| # | 缺陷 | 修复锚点(文件#行为) | 代码现状 | 结论 |
|---|---|---|---|---|
| D-01 | 关联客户添加 404 | OpportunitySubController L71-75 POST /customer/add;OpportunitySubServiceImpl#addCustomer L87-125 |
端点+必填校验(66001)+重复预检(66011 L109-110)+isPrimary 降旧主+快照回写+ROW_ADD 日志全在位 | ✅ |
| D-02 | 候选客户搜索 404 | SubController L78-81 POST /customer/search;SubServiceImpl#searchCustomers L128-137 |
searchCandidatePool 分页 + keyword + NOT IN 排除已关联(快照池降级口径) |
✅ |
| D-03 | 设主要意向 404 | SubController L84-91;SubServiceImpl#setPrimaryCustomer L141-166 | 三步事务(降旧主→置新主→refreshPrimarySnapshot 主表回写)+ 已是主要幂等 L155-157 + FIELD_CHANGE 日志 |
✅ |
| D-04 | 团队成员添加 404 | SubController L226-230 POST /team/add;SubServiceImpl L353(守卫)/addTeamMembers |
批量去重保序、全重拒 66012、未知用户 66001、快照服务端取、ROW_ADD | ✅ |
| D-05 | 团队成员移除 404 | SubController L241-246 POST /team/delete;SubServiceImpl#deleteTeamMember L447-465 |
负责人行拒 66013(L455-457)+ 软删 deleteKey=id, deleted=1 + ROW_DELETE |
✅ |
| D-06 | 团队成员编辑 404 | SubController L233-238 POST /team/update;SubServiceImpl#updateTeamMember L396-443 |
直接换人(目标已在队 66012)+ 负责人行三重锁 66013(换人 L406 / 角色 L425 / 权限 L429,仅 duty 可改 L436) | ✅ |
| D-07 | 暂缓态可编辑 | OpportunityActionGuard#ensureNotPaused L44-50(66003);接线 grep=17 调用点 |
SubServiceImpl ×14(含票 12 workplan 三写入口 L492/520/546)+ edit(DetailServiceImpl L84)+ 方案卡 save/submit(SchemeCardServiceImpl L122/228);focus/touch 不拦、close 不拦(D-08 翻案)符合裁决 | ✅ |
| D-08 | 暂缓态可关闭(翻案) | 裁决:PRD §3.2 E6「2,3→4」合法边 | 无关闭拦截代码 = 正确形态;e2e 断言已按裁决反转(票 05/09) | ✅(非缺陷) |
| D-09 | 禁领规则未生效 | OpportunityActionGuard#ensureClaimAllowed L59-72(66014,match(ownerDeptId),allowFreeClaim null/≠1 保守禁);OpportunityTransitionController claim L44 / claim-batch L57-59(全量预检) |
claim/claim-batch 接线在位;release/assign 不拦(裁决:分配是禁领替代路径);CODE_OPP_CLAIM_FORBIDDEN=66014 在 OpportunityConstants L25 |
✅ |
| D-10 | 阶段模板编辑发布中 50001 | OpportunityStageTemplateServiceImpl#resolveDraft 第三分支 L283-295 |
insert 前清三毒(setId(null)+setCreateTime(null)+setUpdateTime(null) L286-288,注释标 D-10) |
✅ |
| D-11 | 方案卡模板同构 50001 | OpportunitySchemeCardTemplateServiceImpl L226-238 |
清三毒 L229-231(注释标 D-11) | ✅ |
| D-12 | 公海规则同构 50001 | OpportunityPoolRuleServiceImpl L135-148 |
清三毒 L138-140(注释标 D-12) | ✅ |
| D-13 | owner_dept_id 恒空 | crm-opportunity/owner/ 三件套(OwnerSnapshot record / OwnerSnapshotResolver 接口 / OpportunityOwnerSnapshotResolverImpl,bean 名冲突防避注释在位);消费方:OpportunityCreateServiceImpl L87(创建落快照)/ OpportunityCreationPortImpl L50-52(线索转入缺失兜底)/ OpportunityTransitionController 五端点(claim L46 / claim-batch L61 / assign L75 / assign-batch L87 / handover L168,快照参数已删、服务端 of() 解析) |
快照跟人走(claim/assign=新负责人,handover=完整过户);TransitionImpl claim/assign/handover 均 .set(OwnerDeptId, cmd.ownerDeptId()) |
✅ |
| D-14 | 必填校验 500 类 | create:OpportunityCreateServiceImpl L56-64 六必填逐字段 66001(requireText L120-125);edit:OpportunityDetailServiceImpl#edit L75-82 merged(dto,existing) 合并校验 |
6 字段(名称/来源/招标形式/省/市/属地)×正负路径;edit null=保留原值、空白拒 | ✅ |
| D-15 | 公海看板 summary 未过滤 | query/OpportunityViewFilter(六视图 switch + providesStatusCondition,PUBLIC_POOL 由分支供状态条件避恒假 AND);OpportunityCollabServiceImpl#applyBoardViewFilter L142-148 |
board 两端点共用单一事实源;viewType 可选参数默认 MINE | ✅ |
| D-16 | detail 六联动字段 null | OpportunityDetailServiceImpl fillEchoFields:followed L114 / lastFollowTime L125 / schemeCardStatus+schemeBudget L140-144(快照优先+存量兜底实时查)/ stageStayDays L159 / nextStageName L165 |
6 字段全落位(票 02 收窄 4 + 票 09 补 2,与 page 同源口径) | ✅ |
| D-17 | 方案卡提交后主表未回显 | OpportunitySchemeCardServiceImpl L265-271 |
事务内 LambdaUpdateWrapper 显式 set 两列(SchemeCardStatus=SUBMITTED + SchemeBudget),规避乐观锁实体 updateById 坑 |
✅ |
| D-18 | surveySeq 调用方传(翻案) | 裁决:原型「*勘察次数」必填下拉 | addSiteSurvey L154 surveySeq 保持 @RequestParam 必填 = 正确形态 |
✅(非缺陷) |
| D-19 | 勘察说明非必填(翻案) | 裁决:原型无星号 | L156 surveyDesc required=false 保持 = 正确形态 |
✅(非缺陷) |
| D-20 | oplog 流转不留痕 | OpportunityTransitionImpl#recordStatusFlowOplog L332-349(FIELD_CHANGE + OplogLogType.STATUS_FLOW + fieldName=opp_status + 旧/新值 + label 文案 + MANUAL/SYSTEM 归因) |
grep 调用点 ×10 = E1 领取 L134 / E2 分配 L154 / E3 抛池 L103 / E4 暂缓 L197 / E5 恢复 L221 / E6 关闭 L238 / E7 重开 L252 / E8 转项目 L267 / E9 自环(旧=新) L292 / E10 回收 L177,流转边全覆盖 | ✅ |
| D-21 | bizType 契约矛盾 | OpportunitySubController L53-58 ATTACHMENT_BIZ_TYPES(Set.of 四值封闭)+ L194-199 判空校验 66001 |
四值 OPP/FOLLOW_UP/SITE_SURVEY/SCHEME_CARD 与 OpportunityConstants 同源;Set.of contains(null) NPE 先判空教训注释在位 |
✅ |
| D-22 | versions 实体直出泄露 | 三族 Controller versions:Stage L86-95 / SchemeCard L92-102 / PoolRule L85-94 |
出参全部 DTO 化(fromEntity 白名单,剥 creatorId/updaterId/deleted),三个 OpportunityXxxVersionDTO 新文件在位,注释标 D-22/ADR-0017 |
✅ |
| D-13+票12 | 工作计划四端点 | OpportunitySubController L261-288(list/add/update/delete);OpportunitySubServiceImpl L470-553 |
list(deleteKey=0, createTime 升序)/ add(oppId+planContent 必填≤1000)/ update(planStatus 值域 0/1 封闭 66001、部分更新显式 set、finishTime 0→1 回填 1→0 清空)/ delete(软删+ROW_DELETE);三写入口全接 requireOpp(66002)+ensureNotPaused(66003);DTO deadline 带 @DateTimeFormat |
✅ |
C. 次要瑕疵与工作区观察(不阻塞验收)
- ⚠ D-01 方法 javadoc 残留旧方案(§A6)——行为正确、注释过时,建议下次触碰该文件时顺手修正(也可留待打字窗口,本图不为此开票)。
- ⚠
OpportunitySubControllerL36-37import java.util.Set;重复两次——javac 合法(无错),纯整洁性问题。 - ⚠ 错误码 64018 两族同值:
CODE_STAGE_TPL_SEED_PROTECTED(阶段模板,L99)与CODE_SCHEME_TPL_INVALID(方案卡模板,L139)均为 64018——D-01 插入 64018 时方案卡族区间注释未顺延。既有债务,排查日志时两族错误码需按接口路径区分,不在本图修。 - 工作区状态盘点(git status,20260831):
- 票 12 增量在位且完整:untracked
OpportunityWorkPlanAddDTO/UpdateDTO2 文件 +OpportunitySubController/OpportunitySubServiceImpl/IOpportunitySubService的MM二次未暂存修改(workplan 节)+OpportunitySubServiceImplTest(30 用例,AM)。待打包增量 = 工作区 vs HEAD(938aed9…32ac292 已含 opportunity-fix + bugfix 部分 commit;bugfix 主体为已暂存未 commit)。 - 并行 effort 混入提示:
crm-auth的ResourceServiceImpl(+Test)存在 auth-perms effort 的未暂存改动——本图票 02 起服打包(clean package)会把这批改动一并带进 fat jar;crm-auth 域不受商机验收影响但需知悉。 logs/crm-app.log存在DU(unmerged)状态残留——log 文件本身已被32ac292停止跟踪,不影响构建,但首次 commit 时需留意。
- 票 12 增量在位且完整:untracked
- 既有红灯豁免项:crm-auth
ResourceServiceImplTest.save_editCatalog_noButtonFields(map Notes 豁免口径)——auth-perms 票 02 正在处理中,本轮 mvn test 实测结果见 §D。
D. 全量单测(mvn test,10 模块 reactor)
20260831 实测:BUILD SUCCESS,MVN-TEST-EXIT=0,合计 873/0/0(Failures/Errors/Skipped),Total 01:26 min。 日志:mvn-test.log。
| 模块 | Tests | F/E/S |
|---|---|---|
| crm-base | 38 | 0/0/0 |
| crm-file | 84 | 0/0/0 |
| crm-auth | 210 | 0/0/0 |
| crm-dict | 51 | 0/0/0 |
| crm-rule | 134 | 0/0/0 |
| crm-preference | 16 | 0/0/0 |
| crm-lead | 131 | 0/0/0 |
| crm-opportunity | 209 | 0/0/0(与票 12 Answer 209/0/0 一致) |
| crm-app | — | (无测试段) |
- 豁免项失效(好消息):map Notes 的既有红灯
ResourceServiceImplTest.save_editCatalog_noButtonFields本轮未复现——crm-auth 210/0/0。原因:该用例已被 auth-perms effort 票 02(perms-hardening,工作区未暂存改动)改写为「编辑 catalog 时 perms 只读保留 DB 原值」语义(Test L434-452),红灯随语义改写消失。商机域验收不受影响,豁免口径自动解除。 - 工具链:mvn=
D:\apache-maven-3.9.9\bin\mvn.cmd(非 bugfix 票面写的 IDEA 捆绑路径,已失效),JDK17=C:\Users\luowj\.jdks\jdk-17.0.15。
变更追溯
- 复核输入:
.scratch/opportunity-fix/map.md(最终定案节)、.scratch/opportunity-bugfix/issues/02/03/04/05/06/09/12、retest-verdicts.md - 复核方式:纯静态(Read/Grep 源码锚点比对),不起服;运行时行为验证归票 02(全量 E2E 重跑)