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.
 
 
 
 
 

6.7 KiB

02 lead→opp port 消费侧契约落地

Type: grilling Status: resolved

Question

商机侧实现 crm-lead/port/outbound/OpportunityCreationPort(线索 ticket 08 已定稿的出站契约),把"线索转商机"这条断线接通。契约既定,本票钉的是商机侧落地细节

  • 幂等落点UNIQUE(source_lead_id) 建在商机主表哪个字段;重复转商机(幂等命中)时返回既有商机 id 还是抛异常。
  • 带出快照的落库CreateOpportunityCmd 的 sourceLeadName/sourcePhone/sourceProductCode/ownerUserId/ownerDeptId/poolId 分别落到商机主表哪些字段;哪些是快照(不随线索变)哪些是引用。
  • 事务边界:port 同步、在线索事务内触发、失败抛 OpportunityCreationException 使线索整体回滚——商机侧建表/写子表的哪些步骤必须在这个同步事务内完成,哪些可异步。
  • 直接创建商机入口(跳过线索)与"由线索转入"入口的字段差异:source_lead_id 可空?两条入口如何共用建商机逻辑。
  • 转商机成功后线索侧写 lead_history(转商机)用到的商机 id 由 createOpportunity 返回——确认返回值语义。

不改线索侧契约(已定稿);只定商机侧实现规格。

Answer

四簇全部拍板(grilling,产品逐条确认)。:grill 过程中冒出一处必须改线索契约的决策(意向客户下拉选客户 → 带 customerId),已越出「不改线索契约」的原定边界,产品明确要求改,见「契约变更」段 + 派生新票。

簇 A — 幂等落点

  • 幂等键 = 商机主表 UNIQUE(source_lead_id)source_lead_id IS NULL(直接创建)不参与唯一约束,可多条并存。
  • 幂等命中 = 安静返回已有商机 id(写法一,真幂等),不抛异常——OpportunityCreationPort javadoc 的「幂等语义」即此意。重复转商机(重试)当作成功,返回既有商机 id。
  • 并发防护:两个转商机事务同时命中同一 source_lead_id,先查都查不到、都 insert,DB 唯一索引让后提交者抛 DuplicateKeyException。商机侧须捕获唯一键冲突 → 回查既有商机 → 返回其 id,不外抛。这样「安静返回已有 id」在并发下也成立。
  • 返回值语义:createOpportunity 返回的 Long = 商机 id(新建或既有),线索侧据此写 lead_history(转商机)。

簇 B — 带出快照落库(cmd 字段全部落库,无一丢弃)

Cmd 字段 落主表 引用/快照 说明
opportunityName 商机名称 商机自有业务字段
industryCode 行业 字典码
partyA 甲方 自由文本
intendedCustomer 意向客户名 快照 客户名快照(见契约变更:与新 customerId 并存,走法 B)
regionCode 地区 国标码
remark 备注
ownerUserId owner_user_id 引用 领取人 = 归属本身
ownerDeptId 领取人所属部门 快照 转商机那刻部门;领取人调岗不变;抛公海清领取人后仍可归档/报表
sourceLeadId source_lead_id 引用(幂等键) 来源线索血缘
sourceLeadName 来源线索名快照 快照
sourcePhone 联系电话快照 快照
sourceProductCode 需求产品码快照 快照
poolId 来源公海池 id 引用/归档 存下来,纯血缘归档、用于后续排查问题;不参与商机自身公海逻辑(票 05 另有商机公海规则)

簇 C — 两条入口共用建商机核心逻辑

  • 商机侧一个内部建商机核心方法(建主表行 + 初始状态/阶段 + 初始操作日志 + 子表);线索转入 / 直接创建两条入口共用,进入平权(票 01)。

  • 差异只在入口层(进核心逻辑前):

    差异点 线索转入 直接创建
    source_lead_id 有值 NULL
    oppSource(商机来源) 默认「线索转入」 用户弹窗选
    来源快照(线索名/电话/产品码/池 id) 从 cmd 带 全空
    owner_dept_id 快照 cmd 传的 当前用户当前部门
    幂等检查 要(查 source_lead_id 不要
  • oppSource 默认「线索转入」由商机侧入口层填CreateOpportunityCmd 无此字段,不回头改线索契约加它)。

  • 新商机 = 状态「推进中」+ 阶段「模板第一步」(阶段模板细节留票 06,本票只定「落第一步」规则)。

  • 直接创建入口的完整 API/字段规格留票 03;本票只钉「两条入口共用核心逻辑 + 差异表」这条边界。

簇 D — 事务边界 + 转商机时的子表

  • 必须同步(线索事务内,失败抛 OpportunityCreationException → 线索整体回滚)
    1. 幂等检查(查 source_lead_id
    2. 建商机主表行(全部快照字段 + 初始状态/阶段)
    3. 写一条初始操作日志(「由线索转入创建」)
    4. 建团队成员一条:领取人 = 团队成员,项目角色 = 商机负责人
    5. 建关联客户一条:关系标记 主要意向客户customer_id = cmd 带来的 customerId(引用)+ intendedCustomer 客户名快照
  • 可异步(事务提交后,失败不回滚线索):通知/提醒(「你有新商机」)、建群/推送(本 out of scope)、其他非核心派生数据。

契约变更(越出「不改线索契约」原边界,产品明确要求)

  • CreateOpportunityCmd 新增 customerId(Long,必填)intendedCustomer 保留为客户名快照(走法 B:引用 + 快照并存,与 CONTEXT.md「关联客户」术语一致)。
  • 线索转商机弹窗:意向客户改为下拉选客户(选中拿到 customer_id)——线索转商机前置要求「必须有意向客户」。
  • 项目角色首项:「销售负责人」→ 「商机负责人」(改 crm-opportunity/CONTEXT.md「团队成员」术语)。
  • ⚠ 客户实体归 A4 客户模块(未建)。此变更依赖「线索侧下拉能查到客户列表」的能力落地——契约字段/领域决策本票钉死,真正改 crm-lead 代码 + A4 客户下拉能力另开新票.scratch/opportunity-module/issues/11-customerid-in-create-cmd.md)。

已核实事实

  • OpportunityCreationPort / CreateOpportunityCmd / OpportunityCreationException 现存于 crm-lead/src/main/java/com/crm/lead/port/outbound/(线索票 08 定稿),返回 Long = 商机 id。
  • crm-opportunity/CONTEXT.md 现存,「关联客户」术语已写「引用 + 快照」模式,与走法 B 一致。