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.

58 lines
5.6 KiB

7 days ago
# 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)是硬约束:同部门第二条规则发布会拒绝而非自动顶替,禁领→放行切换需先停用旧版。