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.
47 lines
3.7 KiB
47 lines
3.7 KiB
|
3 weeks ago
|
# 08 修复:P1 服务层守卫批次(P1-1/2/3/4)
|
||
|
|
|
||
|
|
Type: task
|
||
|
|
Status: resolved
|
||
|
|
Blocked by: 03
|
||
|
|
|
||
|
|
## Question
|
||
|
|
|
||
|
|
按 ticket 03 的裁决修复 P1 服务层四项(判误报的跳过):
|
||
|
|
|
||
|
|
- **P1-1 反馈提交清草稿**:`applyFeedback()` 提交成功后清除同 `(user_id, lead_id)` 的 DRAFT 行(PRD §6.4:"转为 SUBMITTED"——删除或置状态,按 PRD 措辞与现表结构定,写清注释)。
|
||
|
|
- **P1-2 删除权限**:`deleteLead()` 按 **PRD §3.3** 落地:`删除 = (状态≠已转商机) AND (管理员 OR 创建人)`;激活 `isCreator` 死变量或移除;"管理员判定由 DataScope 兜底"的注释假设要重新论证——DataScope 是读过滤,写守卫必须在 service 里显式判(用 07 号 ticket 选定的管理员判定机制,保持一致)。
|
||
|
|
- **P1-3 EDIT 字段级 diff**:`editLead()` 对可编辑业务字段做 old→new diff,变更项写入 EDIT 历史 detail(字段名/旧值/新值,格式对齐 `LeadHistoryRecorder` kv 机制);无变更时是否仍写 EDIT 由本 ticket 定并写明依据。
|
||
|
|
- **P1-4 反馈入口校验**:按 03 结论补缺——feedbackStatus 枚举合法性(仅 有效/无效,未反馈不可作为提交值);EXPIRED/CONVERTED 等状态拦截若 `LeadTransition.guard` 已兜底则复核单测覆盖,不重复实现。
|
||
|
|
|
||
|
|
**验收**:每项新增针对性单测 + `mvn test`(crm-lead)全绿 + BOM 扫描。
|
||
|
|
|
||
|
|
## Answer
|
||
|
|
|
||
|
|
### P1-1 反馈提交清草稿
|
||
|
|
- `submitFeedback()` 在 `leadTransition.execute()` 成功后,调用 `leadFeedbackMapper.delete()` 清除同 `(userId, leadId, DRAFT)` 的草稿行。
|
||
|
|
- 依据 PRD §6.4:"草稿随提交转为 SUBMITTED"——`applyFeedback()` 已新建 SUBMITTED 记录,DRAFT 行为残留,此处删除(而非更新状态)避免重复记录。
|
||
|
|
- 单测:`submitFeedback_clearsDraft`——验证 `leadFeedbackMapper.delete(any())` 被调用。
|
||
|
|
|
||
|
|
### P1-2 删除权限
|
||
|
|
- `deleteLead()` 落地 `删除 = (状态≠已转商机) AND (管理员 OR 创建人)`(PRD §3.3)。
|
||
|
|
- `isAdmin = SecurityUtils.hasRole(AuthConstants.ROLE_CODE_ADMIN)`(与 ticket 07 一致)。
|
||
|
|
- `isCreator = creatorId != null && Long.parseLong(creatorId) == currentUserId`。
|
||
|
|
- `!isAdmin && !isCreator` → throw `CODE_NOT_OWNER`(65004)"仅管理员或创建人可删除线索"。
|
||
|
|
- 移除"管理员判定由 DataScope 兜底"的错误注释——DataScope 是读过滤,写守卫必须在 service 显式判。
|
||
|
|
- 单测:`deleteLead_nonAdminNonCreator_rejected`(拒)+ `deleteLead_creatorAllowed`(放行)。
|
||
|
|
|
||
|
|
### P1-3 EDIT 字段级 diff
|
||
|
|
- `editLead()` 对 13 个可编辑业务字段做 `Objects.equals(old, new)` 逐项比较,变更项以 `(fieldName, newVal)` kv 对追加到 `editDetail` 列表。
|
||
|
|
- 调用 `historyRecorder.record(id, EDIT, userId, editDetail.toArray())`——空列表→detail=null(无变更仍写 EDIT,记录编辑意图)。
|
||
|
|
- 新增 `addIfChanged(List<Object>, String, Object, Object)` 辅助方法。
|
||
|
|
- 单测:`editLead_fieldDiff_onlyChangedFieldsInHistory`——验证 history detail 仅含变更字段(leadName+phone),不含未变更字段(consultContent 等)。
|
||
|
|
|
||
|
|
### P1-4 反馈入口校验
|
||
|
|
- `submitFeedback()` 入口校验 `feedbackStatus`:必须为 `FEEDBACK_VALID(1)` 或 `FEEDBACK_INVALID(2)`,否则 throw `CODE_LEAD_INVALID`(65001)"反馈情况必须为有效或无效"。
|
||
|
|
- EXPIRED/CONVERTED 状态拦截:`FeedbackCmd.allowedFromStatuses()` = {CLAIMED, FOLLOWING, VOID},`guard()` 已兜底,不重复实现——仅复核单测覆盖。
|
||
|
|
- 单测:`submitFeedback_invalidFeedbackStatus_rejected`——feedbackStatus=0→拒、不进 transition。
|
||
|
|
|
||
|
|
### 验证
|
||
|
|
- BOM 扫描:2 个修改文件无 BOM。
|
||
|
|
- `mvn test -pl crm-lead -am`:91 tests, 0 failures, 0 errors, BUILD SUCCESS。
|