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

业务规则(crm-rule)

多域规则中心(票 01):线索规则子域(公海池配置 + 行政区划)与商机规则子域(公海规则、后续阶段模板/方案卡模板/有效跟进规则,原型 A7-3-2)分域共住本模块,完全独立无共表无共抽象(范式都不同:池实体 vs 版本化规则配置)。依赖方向单向 crm-rule → (crm-auth / crm-dict)不得反向依赖 crm-lead / crm-opportunity——规则表不知道线索/商机实体存在。

线索规则子域

线索公海池的配置域:公海池实体(归属部门 + 省/市/区)、人员(负责人 / 协作人 / 成员)、领取规则、超时回收 / 失效 / 领取上限配置。公海池表复用 lead 数据范围模块(决策 [K])。

Language

公海池: 线索的归集容器与规则载体,crm-rule 的核心聚合根,存于 lead_pool。定义一个部门下线索的领取规则(回收天数 / 失效天数 / 持有上限 / 每日领取上限)与人员编制。一部门一池UNIQUE(dept_id);池名全局 UNIQUEAvoid: 线索池、公海、资源池、pool(英文单说)

归属部门: 公海池所属的部门节点,dept_id,是「一部门一池」的唯一键。同时冗余 team_dept_id(团队 = 部门树上级节点)。归属部门决定池及池内线索的数据范围天花板。 Avoid: 所属部门、部门、团队部门

负责市场: 公海池覆盖的行政区划,多值——省份多值表 + 市/区多值表两张关联表。存国标 code(varchar(12),支持前缀 LIKE 祖先查询,对齐 sys_region)。同一部门的多个市场取并集在同一个池里(一部门一池),不拆多池。 Avoid: 覆盖区域、地区、辖区

负责人: 公海池的主管理人,池-人绑定表中 role=OWNER。被设为负责人会落一条池维度的行级授权(resource_type=pool),使其能越过部门天花板看到池内线索。负责人身份不授予池配置写权(决策 [E])——改池配置走功能权限 × 数据范围。 Avoid: 池主、管理员、owner(owner 在 crm-lead 是领取人)

协作人: 公海池的协助管理人,池-人绑定表中 role=COLLAB。与负责人一样落池维度行级授权(只读,越过部门天花板看池内线索)。移出协作人名单那一刻即失效,授权行硬删(决策 [PRD-3])。 Avoid: 协助人、副负责人、collaborator

成员: 有资格领取该池线索的销售集合。动态推导、不落表——成员 = 归属部门的部门子树内全部用户,按组织架构实时算。不是池-人绑定表里的行(绑定表只存 OWNER / COLLAB)。 Avoid: 池成员表、领取人白名单、参与者

回收天数: 池配置字段 recycle_days,喂给线索的回收计时 N。DB DEFAULT = 7。 Avoid: 超时天数、N、recycle

失效天数: 池配置字段 expire_days,喂给线索的失效计时 M。DB DEFAULT = 180。 Avoid: 有效期、M、expire

持有上限: 池配置字段 hold_limit,单个销售在本池最多同时持有的线索数。只算「已领取 + 跟进中」,不含已转商机 / 过期失效 / 作废。DB DEFAULT = 200。 Avoid: 最大持有、上限、hold

每日领取上限: 池配置字段 daily_claim_limit,单个销售每个自然日(DATE(op_time) = CURRENT_DATE)在本池最多领取的线索数。DB DEFAULT = 10。 Avoid: 日领取限、领取限额、daily limit

池删除保护: 公海池软删;但池下有非终态线索时禁止删除(非终态 = 未分发 / 待领取 / 已领取 / 跟进中)。防止孤儿线索。 Avoid: 级联删除、强制删除

池占用查询端口: 公海池删除守卫的跨模块出站契约 PoolLeadOccupationPort(crm-rule 定义,crm-lead 实现,ADR-0025)。方法 hasActiveLeads(poolId) 返回 boolean——true=池下有非终态线索(禁止删除)。与 OpportunityCreationPort(crm-lead 定义等商机实现)方向相反的同型 outbound port;crm-rule 通过 ObjectProvider 可选注入,port 未实现时 fail-safe 拒删。 Avoid: 占用检查服务、lead 查询接口(要点是「crm-rule 声明契约、crm-lead 实现、依赖倒置不破坏方向」)

池批量删除: deletePoolBatch 一行委派 crm-base BatchRunner.run(ids, self::deletePool, PoolBatchFailItem::bizOf, PoolBatchFailItem::unknownOf)(ADR-0028)——非原子、逐条经 self 代理走独立事务、部分成功;失败项 PoolBatchFailItem(poolId + PoolBatchFailReason + message)与 code→reason 翻译、兜底文案(「删除失败」)由本域自持(ADR-0023 D5)。曾内联的同构编排(与 crm-lead 旧 runBatch 逐字重复)已删除——批量编排协议的家在 crm-base。 Avoid: 批量删除服务、池批处理(要点是「编排委派 BatchRunner + 失败语义留在域内」)

商机规则子域(票 05 起)

商机公海规则: 商机公海/回收/领取/提醒的版本化规则配置 opportunity_pool_rule(票 05 原型 A7-3-2-5):同一 rule_code 多版本每版本一行,范式 = 草稿/发布中/已停用 + version_no(与票 06 阶段模板、票 07 方案卡模板同族 V-CONFIG),不是 lead_pool 那种「一部门一池」实体(无省/市/区地理维度、无领取/持有上限)。五配置项:allow_manual_pool / auto_recycle_enabled+recycle_days / allow_free_claim / recycle_remind_enabled+remind_days(提醒依赖回收启用,remind_days < recycle_days 硬校验)。适用范围两档:所有部门通用(可设默认)/ 对应部门专用(适用部门多值子表 opportunity_pool_rule_dept)。 Avoid: 商机公海池(无池实体)、商机池、线索池

规则版本状态机: IOpportunityPoolRuleService 承担的版本生命周期约束(票 05「二」):同 rule_code 仅一草稿一发布中;发布使原发布中转停用、原发布中默认自动取消默认(默认唯一是自动顶替非拒绝);发布时校验部门覆盖唯一(一个部门只被一条发布中规则覆盖,重叠拒发 64012)——保证匹配「最低层级必唯一命中」;编辑发布中/停用版本→生成新草稿(版本号 minor 顺延 V1.0→V1.1,同 code 已有草稿则拒 64011);复制→独立新规则(新 rule_code + V1.0 草稿);仅草稿可删。版本号/编码系统生成只读。三票(票 05/06/07)逐字重复的版本机制——minor 顺延、编码顺延、纯状态迁移——收敛于 service.impl.VersionedConfigSupport 基类(三 ServiceImpl 继承,领域校验/子表替换仍各票自持);三票版本关联子表的版本列统一 rule_version_id / template_version_id(快照子表如 opportunity_scheme_card_field.template_id 保持原名)。 Avoid: 商机状态机(那是 opp_status 归属流转轴,两回事)、直线版本号(minor 顺延非末尾+1)

公海规则匹配引擎: OpportunityPoolRuleMatcher(快照式 API:loadPublished() 一次加载全部发布中规则 + 部门子表,match(ownerDeptId) 纯内存匹配):部门专用(apply_scope=2 命中)优先 → 通用默认(apply_scope=1 且 is_default=1)兜底 → 非默认通用不兜底(null = 无规则不动作)。公海规则实时匹配不锁版本(与阶段模板锁版相反,PRD §5.4)——每次 Job 扫描重载快照。供商机侧维护 Job 批量扫描,避免逐商机查库。 Avoid: 锁版本(公海规则实时)、按查看人部门匹配(锚点是商机自身 owner_dept_id)

方案卡字段库种子: SchemeFieldDefInitializer(@Order(15))首装植入两样东西:系统字段库 opportunity_scheme_field_def(16 项,含 site_survey_files 现场勘察资料 ATTACHMENT,delete_key 软删唯一索引)+ 全公司通用兜底模板(固定编码 OPP_SCHEME_TPL_01,发布中 8 字段,PRD §7.2/附录 A:建卡入口无候选时兜底;编码与 nextCode 顺延兼容——首装种子持 01、后续新建从 02 起)。幂等键=模板编码,任意状态(含已停用)存在即跳过——管理员停用兜底模板后重启不复活。 Avoid: 前台配置接口建字段库(种子属首装初始化)、停用后重启复活(幂等键含已停用)

阶段展示名投影: IOpportunityStageTemplateService#describeStages(stageIds)stageId → StageDisplay{currentStageName, nextStageName} 的批量投影(名称回显)。「显示名 = customNodeName 优先、空则带入 opp_stage 字典名」与「同版本内按 seqNo 升序求下一节点」两条领域规则由 crm-rule 内部独占;对外只发 StageDisplay 两个展示名字符串,不再把 OpportunityStageNode 实体与排序/字典兵底知识泄露给消费方(crm-opportunity 展示层)。批量去重(distinct templateId 取整版、字典名去重)在本服务内完成,避免 N+1。 Avoid: 取节点实体自算显示名(知识泄露)、逐条 describeStage(批量一次过)

客户规则子域(票 09;查重设置 customer-rework 票 04)

超期未跟进提醒规则: 客户规则族全局单例配置之一 customer_reminder_rule(票 09 / issues-10 §B):单行表 id 固定=1,CustomerReminderRuleInitializer 首装植入默认行(对称 StageTemplateInitializer 兜底范式,幂等键=单例行存在)。不套 V-CONFIG 版本化(chart D4)——无版本号/状态机/rule_code,保存=全量覆盖即生效(开关缺省视为禁用),校验 firstTriggerDays/secondIntervalDays > 0(64023,错误码 64xxx 客户规则族段)。五配置项:masterEnabled / firstTriggerEnabled+firstTriggerDays(默认 30)/ secondIntervalEnabled+secondIntervalDays(默认 7)。RBAC 功能权限 customer.reminder.rule(菜单挂「客户管理」目录)。契约 POST /api/rule/customer/reminder/save + GET /api/rule/customer/reminder(customer-rework 票 02 扁平动词化,原 PUT 已废);crm-rule 无 oplog 基建,保存以应用日志记操作人+覆盖后配置。消费方 crm-customer CustomerReminderJob(缺失/总开关关 → 整轮跳过)。 Avoid: 商机公海规则(那是版本化范式)

客户查重设置: 客户规则族第二个全局单例配置 customer_dedup_rule(customer-rework 票 04 / R8 补 a7-3-3-2 页面端点;上游 D4-rev2 拍板 B)。单行表 id 固定=1,CustomerDedupRuleInitializer 首装植入默认行(全开关启用 + 模糊匹配 + 标准 80% 阈值——a7-3-3-2 出厂口径),幂等键=单例行存在;同样不套 V-CONFIG,保存=全量覆盖(开关缺省视为禁用、匹配方式缺省回模糊、阈值缺省回 80),校验 nameMatchMode ∈ {1,2}、similarityThreshold ∈ [0,100](64023)。五配置项:masterEnabled(总开关仅控名称/电话)/ nameEnabled+nameMatchMode+similarityThreshold(名称:1精确 2模糊)/ phoneEnabled(电话软提示,D26)。统一社会信用代码为系统强制规则,无配置列(a7-3-3-2 §3,消费侧恒开)。RBAC 菜单「客户查重设置」挂「客户管理」目录(CustomerDedupRulePermissionInitializer,@Order 19)。契约 GET /api/rule/customer/dedup + POST /api/rule/customer/dedup/save(表单绑定);tag A7 后台管理/客户管理设置/查重设置。消费方 crm-customer RuleBackedCustomerDedupSettingProvider(@Primary,Java service 直依赖;总开关∧单项开关→名称/电话,匹配方式驱动 CustomerDedupService 精确/模糊分支——精确=标准化全等、模糊=D21 ngram port;单例缺失回退 DefaultCustomerDedupSettingProvider 出厂值)。 Avoid: 信用代码开关字段(强制规则不可关)、导入路径消费匹配方式(D4-rev2 消费范围仅新增/编辑内建查重)、算法层标准化全套(全半角/后缀移除随 D21 迭代)

提醒链: 确定性可推导的提醒计划序列(issues-10 §C,无需存「已发首次」状态):第 0 次 plan = anchor + firstTriggerDays,第 k 次 plan = anchor + firstTriggerDays + k × secondIntervalDays。锚点 = 客户 last_valid_follow_time(成为有主时刻,Q15 拍板 A:新建直接指派=create_time、公海领取时赋锚、每次跟进刷新)。Job 每轮每客户只补下一条未建的到期提醒(不批量堆历史);同 (customer, notice_type, plan) 任意状态占位永不重写;锚点被刷新 → 旧锚点未发提醒置已失效(payload.anchor 比对,解析失败保守不动作)。只落 customer_pending_notice 待发不发送(平台通知能力 spin-out)。 Avoid: 已发首次状态存储(链可推导)、剩余天数伪状态(payload 无)