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.
 
 
 
 
 

5.6 KiB

05: P1 修复 C — 暂缓态写拦截(D-07/08)+ 禁领规则接线(D-09)

Type: task Status: resolved Blocked by: 02

任务

A. D-07/08:暂缓态商机可编辑/可关闭

  • PRD §3.3 状态边界:暂缓态不允许编辑、不允许关闭(上轮实测两路都放行了)。
  • 修法:在编辑与关闭两条路径的状态校验里补暂缓拦截(错误码对齐既有状态机校验家族——参考推进中→关闭等的既有校验实现,别发明新风格)。
  • 注意:票 02 若裁决原型 v29 对暂缓态按钮有不同口径(比如原型批注说暂缓可以编辑),以裁决为准调整本票范围。

B. D-09:禁领规则(allowFreeClaim=0)未生效

  • 现象:发布「禁领」公海规则后,用户仍能 claim 领取——规则只影响回收 Job,不影响领取。
  • 根因:PoolRuleMatcher.loadPublished() 只被 OpportunityMaintenanceJob 消费;claim/release 路径未接。
  • 修法:claim(领取)路径接入规则校验——按商机所属部门匹配部门专用规则(owner_dept_id,依赖票 03 修好),无部门专用规则走 isDefault 规则;规则 allowFreeClaim=0 → 拒绝领取(业务码提示「该商机所属部门配置了禁领规则」)。release(抛公海)是否也受规则约束按票 02 裁决口径(默认不受,抛是主动行为)。
  • 性能注意:matcher 已有 loadPublished 缓存机制(Job 在用),claim 路径直接复用同一 matcher/缓存,别每次领取全表扫规则。

验收

  • 暂缓态:edit 返回业务码拦截;close 返回业务码拦截;恢复正常态后两操作恢复可用。
  • 禁领:发布禁领规则(部门专用 + 默认两种)后 claim 被拒且错误信息可读;allowFreeClaim=1 正常领取;无任何发布中规则时不受影响(回归确认)。
  • e2e-core.py F 段(状态流转)+ e2e-rules.py U03 段回归。
  • 单测:暂缓拦截 ×2 + 禁领命中/未命中 ×3。

Answer

已完成(2026-08-30)。范围按票 02 裁决调整:D-08 翻案剔除,D-07 口径扩大为「一切编辑操作全禁」。

实现

  • OpportunityActionGuard(state/,新组件,对齐状态机「业务前置校验归调用方」分工):
    • ensureNotPaused(opp):暂缓中(3) → 66003「暂缓中的商机不允许此操作,请先取消暂缓」;复用调用方已查实体零额外查询。
    • ensureClaimAllowed(oppId):查商机(null→66002)→ matcher.loadPublished().match(ownerDeptId) → 规则 allowFreeClaim≠1(含 null 保守禁)→ 新码 66014「该商机所属部门已配置禁领规则,无法自由领取,请联系管理员分配」。
  • D-07 接入 13 写端点(阶段切换既有 66005 不动,focus/touch 用户行为日志不拦,D-08 剔除故 close 不拦):edit、follow add/delete、site-survey add/delete、attachment add/delete、customer add/set-primary、team add/update/delete、scheme-card save/submit。其中 addFollow 顺带修复「insert 后才查商机且 null 静默容忍」的坏顺序(改为前置 requireOpp + 66002);submitCard 新增 requireOppByCard(脏数据报 66002)。
  • D-09 接入 claim/claim-batch(TransitionController):claim 单领前置校验;claim-batch 全量预检(确定性拒绝先拦,避免部分领取;CAS 类竞态仍由状态机兑底)。release/assign 不拦(裁决:分配是禁领替代路径)。matcher 快照实时查库无缓存问题,性能符合票面要求(复用同一 matcher,非全表扫)。
  • OpportunityConstants:+CODE_OPP_CLAIM_FORBIDDEN = 66014

验证

  • 单测 192/192 全绿(crm-opportunity 全模块):新增 OpportunityActionGuardTest 7 用例(暂缓拦截/放行 + 禁领部门专用/默认/allow=1/空快照/商机不存在)+ OpportunityDetailServiceImplTest 2 用例(edit 暂缓拒/放行,守卫用真实实例)。既有 Sub/SchemeCard 测试兼容性修复(新构造参数补 @Mock guard 保持 no-op;submit 三用例补 opp stub)。
  • 运行时验证 26/26(t05-verify.py):Part P 20 项——14 写端点暂缓态逐一 66003、拦截无副作用(团队/跟进行数不变)、只读放行、resume 后 edit 恢复;Part R 6 项——owner_dept 非空、部门专用禁领 claim 66014、claim-batch 全量预检 66014 且两单均未被领取、放行版发布后 claim/claim-batch 恢复成功。
  • e2e 回归:F14 状态机 22/1⚠/0(⚠=公海计数旁证,seed 残留);e2e-rules PR 段 10/1⚠/0(⚠=规则模块存量 50001 主键冲突,本票范围外)。回归证据另存 report-core-t05-regression.md / report-rules-t05-regression.md。
  • e2e 脚本断言按裁决同步修正:F14「暂缓不可直接关闭」→「暂缓态关闭(E6 2,3→4 合法边,D-08 翻案)」;e2e-rules U03「按缺陷预期放行」→「release-pool 放行(D-09 裁决:仅 claim 接禁领)」。

测试数据修复(本票顺手修)

  • ADMIN(罗伟健)是全库 6047 用户中唯一 dept_id 为 NULL 的,致 D-13 修复的创建快照落 null、部门专用规则永不命中 → 补 dept_id=744841292348915712(广东保伦电子,顶级部门)。
  • F14 的 11 个 e2e-seed 商机被此前清场软删 → 复活并按名字语义复位状态(推进2/暂缓3/关闭4/公海1)。票 11 正式刷 seed 时可直接复用 t05-seedreset.py。

遗留

  • 禁领「默认规则」场景由单测覆盖(不碰 seed 默认位);运行时用部门专用规则验证。
  • 规则「部门覆盖唯一」(64012)是硬约束:同部门第二条规则发布会拒绝而非自动顶替,禁领→放行切换需先停用旧版。