4116 字
21 分钟

2026-06-10|供应风险预警推送完善实现与验证

一、今日主要工作#

  • 按照前一天梳理的《供应风险预警推送完善》开发计划,完成供应风险预警精准推送后端逻辑的代码实施。
  • 将原有“按订单号匹配销售”的推送链路调整为“按产品型号匹配报价单 / 订单,再提取销售人员并创建门户通知”的新链路。
  • 新增 SCM 数据源下的供应风险查询 Mapper,完成未下单报价单查询和已下单未发货订单查询两类 SQL 实现。
  • 改造 PortalSupplyRiskService 中预警创建后的推送路由,支持 SUPPLY_RISKEOLORDERED_RISK 三类预警类型分别走不同查询逻辑。
  • 实现 seller 字段解析、产品型号关键词拆分、销售用户去重和通知创建逻辑,去除原先对 orderId 和 sales 角色过滤的依赖。
  • 完成供应风险预警推送链路的本地功能测试、边界测试和回归测试,共执行 46 个测试用例,核心功能链路通过验证。
  • 在生产数据验证过程中发现 fcst_price_check_order 报价单同步表已停用,当前实现代码已完成,但上线需要等待 CPQ 提供可替代的报价单查询接口。
  • 沉淀实现产出文档,记录需求背景、数据源探索、代码改动、测试结果、当前阻塞和后续 CPQ 接口替换方案。

二、核心完成内容#

1. 模块开发与功能实现#

今天的主要工作不再停留在方案设计阶段,而是基于前一天的开发计划进行了实际编码实现。核心目标是修复供应风险预警在无订单号场景下无法推送的问题,并将推送对象从“订单处理人”调整为“产品型号相关销售”。

原有链路中,供应链交付组创建预警后,系统会调用 resolveOrderSalesUserIds(orderId)

创建预警
→ resolveOrderSalesUserIds(orderId)
→ Oracle cux_om_option_tl.processor
→ SCM sys_user 匹配
→ sales 角色过滤
→ portal_supply_risk_notification

该链路在有订单号时可以做到按订单精准推送,但当预警不关联具体订单号时会返回空列表,导致预警创建成功但没有任何销售收到通知。今天的实现将主链路改为:

创建预警
→ 读取 warningType 和 productModels
→ 按产品型号匹配报价单 / 订单
→ 从 seller 字段提取销售工号
→ 匹配 sys_user.user_id
→ 去重后写入 portal_supply_risk_notification

本次实现保持 API 入口不变,仍使用:

POST /api/portal/supply-risk/alerts

Controller 和数据库主表结构暂不调整,主要改造集中在查询 Mapper 和 Service 层。这样可以在不大规模影响前端和接口契约的前提下,先完成后端推送链路增强。

2. 新增 SupplyRiskQueryMapper 查询能力#

今天新增了 SupplyRiskQueryMapper.java,放在 com.sangfor.pangugong.mapper 包下,并使用 @ScmMapper 绑定 SCM 数据源,保证查询能够访问 fcst_price_check_orderoms_order_data 两张 SCM 业务表。

该 Mapper 主要提供两个查询方法:

  1. selectUnorderedQuotesByProductName(keyword)
    用于 SUPPLY_RISKEOL 场景,按产品名称关键词查询未下单报价单。

  2. selectUnshippedOrdersByProductName(keyword)
    用于 ORDERED_RISK 场景,按产品名称关键词查询已下单但未完全发货的订单。

其中,未下单报价单查询逻辑为:

product_name LIKE keyword
+ 报价单审批状态满足要求
+ 申请时间在指定窗口内
+ seller 不为空
+ 报价单号不为空
+ NOT EXISTS oms_order_data.costApprovalNo

已下单未发货查询逻辑为:

product_name LIKE keyword
+ fcst_price_check_order.price_approval_order_number = oms_order_data.costApprovalNo
+ seller 不为空
+ orderState != 30

其中 orderState=30 表示已完成或已关闭,因此 orderState != 30 用于表示未完全发货或仍在履行中的订单。

3. 改造 PortalSupplyRiskService 推送路由#

今天重点修改了 PortalSupplyRiskService.createAndPublish() 方法中的推送逻辑。

旧逻辑:

List<String> salesIds = resolveOrderSalesUserIds(req.getOrderId());

新逻辑:

List<String> salesIds;
if ("ORDERED_RISK".equals(a.getWarningType())) {
salesIds = resolveSalesForOrderedRisk(models);
} else {
salesIds = resolveSalesForUnorderedQuotes(models);
}

其中:

  • SUPPLY_RISK:按产品型号匹配未下单报价单,提取报价单 seller;
  • EOL:与供应风险共用未下单报价单链路;
  • ORDERED_RISK:按产品型号匹配已下单但未完全发货的订单,提取订单关联报价单的 seller。

改造后,供应风险预警的推送入口从 orderId 转为 productModels,即用户填写的产品型号。orderId 字段保留兼容旧前端,但后端不再依赖它做推送目标解析。

4. 实现 seller 到系统用户的解析逻辑#

报价单中的 seller 字段格式为“姓名 + 工号”,例如:

刘敏79574
王帅66320

今天实现了 resolveSellerToSysUserId() 方法,负责将 seller 字段转换为系统用户 ID。

核心处理步骤为:

  1. 对 seller 字符串去空格;
  2. 提取尾部连续数字作为工号;
  3. 优先通过 ScmSysUserLookupService.findActiveByCode(code) 精确匹配;
  4. 如果精确匹配失败,再使用 sys_user.code LIKE '%工号' 做后缀回退匹配;
  5. 匹配失败时记录日志并跳过,不影响其他销售推送。

这里没有固定写死 5 位工号,而是提取尾部连续数字,主要是为了兼容生产环境中可能存在的不同工号位数。同时,LIKE 后缀匹配可以兼容 06632066320 这类前导零差异。

5. 实现产品型号关键词拆分#

由于供应链交付组在创建预警时可能一次输入多个产品型号,今天新增了 splitProductKeywords() 方法,用于将 productModels 拆分为多个查询关键词。

当前支持以下分隔方式:

  • 换行;
  • 英文逗号;
  • 中文逗号;
  • 英文分号;
  • 中文分号;
  • 多种分隔符混合输入。

例如:

AC-1000
S5000-24P
EDS-1210

或:

AC-1000,S5000-24P;EDS-1210

都会被拆分为多个产品型号关键词,分别查询报价单或订单,并最终对销售用户进行去重。

6. 删除旧推送方法并保留兼容字段#

本次实现中删除或停止使用了两类旧逻辑:

  • resolveOrderSalesUserIds(String orderId):旧的订单号到 Oracle processor 再到销售用户的解析链路;
  • listSalesSysUserIds():旧的全量 sales 推送方法。

同时,SupplyRiskAlertCreateRequest.orderId 字段没有直接删除,而是标记为 @Deprecated,用于兼容旧前端请求结构。后续前端适配完成后,可以再进一步清理该字段。

此外,本次通知创建时不再过滤 sales 角色。原因是销售人员可能尚未开通助手角色,如果通知创建时强制过滤 sales 角色,后续补充角色后仍无法看到历史预警。当前设计是先将通知写入 portal_supply_risk_notification,用户后续获得角色并登录后,可以通过自身 recipientSysUserId 查询到历史通知。

7. 测试验证与问题处理#

今天完成了供应风险预警推送完善的本地测试验证。测试环境为 dev 环境,应用运行在 localhost:5170

由于 dev 环境中的 fcst_price_check_order 数据为历史快照,最新数据停留在 2023 年,因此为验证代码链路,测试时临时将查询条件适配为:

INTERVAL 5 YEAR

并按 dev 数据中的审批状态值调整条件,保证本地能够查到测试数据。

本次共执行 46 个测试用例,其中:

  • 43 个通过;
  • 1 个性能用例未达预期;
  • 2 个因 dev 环境数据无法触发而跳过;
  • 核心功能测试 40 个全部通过。

测试覆盖范围包括:

  • supply 角色创建预警权限校验;
  • 非 supply 角色创建预警拦截;
  • 必填字段校验;
  • 三种 warningType 路由;
  • 默认 warningType 处理;
  • 多产品型号分隔符解析;
  • SUPPLY_RISKEOL 共用链路验证;
  • ORDERED_RISK 与供应风险链路差异验证;
  • 无匹配型号返回 pushCount=0
  • seller 匹配与用户去重;
  • 通知创建、查看、已读和反馈流程;
  • 经理看板、详情、接收人和关闭流程;
  • 角色补充后历史通知可见性;
  • 交付查询、订单关注、角色管理和登录等回归场景。

关键验证结果包括:

  • SUPPLY_RISK 输入 AC-1000 可匹配并推送到 546 名销售;
  • ORDERED_RISK 输入 AC-1000 匹配到 82 名相关销售;
  • VPN-1000 在供应风险与已下单风险两类链路下推送人数存在差异,符合链路预期;
  • 无匹配型号时返回 pushCount=0,预警仍创建但不推送;
  • 通知去重结果正常;
  • seller 字段可正确映射到系统用户,例如 霍高飞30793 能映射到对应 sys_user.user_id

8. 性能与数据源问题定位#

测试过程中发现,dev 环境下单次创建预警耗时约 35 秒。主要原因是 LIKE '%keyword%'fcst_price_check_order 大表上进行模糊匹配,同时 dev 测试为了覆盖历史数据临时放宽到 5 年时间窗口,扫描数据量较大。

更关键的是,在生产验证阶段发现:fcst_price_check_order 报价单同步表已经停用,数据停留在约 2 年前,无法作为后续正式上线的数据源。

因此,今天虽然完成了代码实现和测试验证,但该功能不能直接依赖 fcst_price_check_order 上线。后续需要推动 CPQ 系统提供新的报价单查询接口,用于替代当前已作废的数据表。

9. CPQ 接口替换方案沉淀#

当前项目中已经接入了一个 CPQ 接口:

POST /CPQ/api/quote/open/quotation/item_code

该接口可以按报价单号查询物料编码,但不能满足本次供应风险预警推送的完整需求,因为缺少以下能力:

  • 按产品名称查询报价单列表;
  • 返回报价单审批状态;
  • 返回报价单销售人员;
  • 返回报价单申请时间;
  • 支持按时间窗口过滤近期报价单。

后续如果 CPQ 提供按产品查询报价单的接口,替换方案可以保持 Service 层大部分逻辑不变,只需要将 SupplyRiskQueryMapper 中基于 fcst_price_check_order 的 SQL 查询替换为 CPQ API 调用,再结合 oms_order_data.costApprovalNo 校验订单状态。

也就是说,今天实现的 seller 解析、产品型号拆分、去重、通知创建和 warningType 路由逻辑仍然可以复用,主要需要替换的是报价单数据来源。

10. 接口设计与文档沉淀#

今天同步补充了《供应风险预警推送完善 — 实现产出文档》,对本次开发实施情况进行了整理,内容包括:

  • 业务背景与现有痛点;
  • 三种预警类型的推送对象;
  • 数据源探索过程;
  • 报价单与订单关联关系验证;
  • SupplyRiskQueryMapper 新增查询;
  • PortalSupplyRiskService 改造点;
  • seller 字段解析方案;
  • 产品型号多分隔符解析;
  • 测试环境准备与测试结果;
  • 性能瓶颈;
  • 当前阻塞问题;
  • 后续 CPQ 接口替换方案。

该文档可以作为后续继续与 CPQ 或相关 IT 团队沟通接口能力、评估上线条件和进行二次改造的依据。

三、今日工作产出#

  • 完成供应风险预警推送完善后端代码实现,将推送入口从 orderId 调整为 productModels
  • 新增 SupplyRiskQueryMapper.java,使用 SCM 数据源查询报价单和订单数据。
  • 实现 selectUnorderedQuotesByProductName(),用于 SUPPLY_RISKEOL 场景匹配未下单报价单销售。
  • 实现 selectUnshippedOrdersByProductName(),用于 ORDERED_RISK 场景匹配已下单未完全发货订单销售。
  • 改造 PortalSupplyRiskService.createAndPublish(),根据 warningType 路由到不同销售解析链路。
  • 新增 resolveSalesForUnorderedQuotes()resolveSalesForOrderedRisk()resolveSellerToSysUserId()extractTrailingDigits()splitProductKeywords() 等核心方法。
  • 删除或停止使用 resolveOrderSalesUserIds()listSalesSysUserIds() 旧逻辑。
  • SupplyRiskAlertCreateRequest.orderId 标记为 @Deprecated,保留旧前端兼容性。
  • 完成本地测试验证,共执行 46 个测试用例,核心功能测试通过。
  • 定位性能瓶颈主要来自 LIKE '%keyword%' 大表模糊匹配和 dev 环境 5 年窗口扫描。
  • 发现生产环境 fcst_price_check_order 同步表已停用,明确当前功能需等待 CPQ 接口补齐后再上线。
  • 沉淀《供应风险预警推送完善 — 实现产出文档》,记录实现细节、测试结果、阻塞点和后续替换方案。

四、遇到的问题与解决情况#

1. 旧推送逻辑在无订单号场景下无法推送#

  • 问题:旧精准推送依赖 orderId,当供应风险预警不关联具体订单时,resolveOrderSalesUserIds() 返回空列表,导致没有任何销售收到通知。
  • 处理:将推送入口改为 productModels,按产品型号查询报价单或订单,再从 seller 字段提取销售。
  • 结果:供应风险、产品退市和已下单风险三类预警都可以基于产品型号进行销售匹配。

2. 报价单与订单数据关系需要重新确认#

  • 问题:需要确认产品型号、报价单、订单、销售之间的真实关联链路,避免使用错误表或低覆盖表。
  • 处理:对比 ivsc_order_infooms_order_datafcst_price_check_order,并通过字段注释、项目代码和 CPQ 接口交叉验证 costApprovalNo 与报价单号关系。
  • 结果:确定使用 SCM 数据源中的 fcst_price_check_orderoms_order_data 构建查询链路。

3. seller 字段需要转换为系统用户 ID#

  • 问题:报价单中的 seller 字段是“姓名 + 工号”文本,不是系统用户 ID,不能直接写入通知表。
  • 处理:实现尾部连续数字提取算法,优先按工号精确匹配 sys_user.code,失败后按工号后缀模糊匹配。
  • 结果:seller 可以转换为 sys_user.user_id,用于创建 portal_supply_risk_notification

4. dev 数据快照过期影响测试#

  • 问题:dev 环境 fcst_price_check_order 最新数据停留在 2023 年,按生产条件中的 3 个月窗口无法查到数据。
  • 处理:本地测试阶段临时放宽时间窗口,并按 dev 数据中的状态值适配查询条件。
  • 结果:完成本地功能链路验证,但正式上线仍需按生产数据源重新验证。

5. 查询性能存在瓶颈#

  • 问题:LIKE '%keyword%' 在大表上进行模糊匹配,dev 环境单次创建预警约 35 秒。
  • 处理:定位瓶颈来自大表模糊查询和测试窗口过大,并记录为后续优化项。
  • 结果:当前逻辑可以验证功能正确性,但正式上线需要结合真实 CPQ 接口和索引方案重新评估性能。

6. 生产报价单同步表已停用#

  • 问题:生产验证发现 fcst_price_check_order 表数据已停在约 2 年前,无法作为正式线上数据源。
  • 处理:保留当前代码实现和测试结果,将数据源问题记录为阻塞;整理 CPQ 接口替换方案。
  • 结果:当前功能实现完成但暂不适合上线,后续需与 CPQ 团队协作补齐按产品查询报价单接口。

五、明日计划#

  • 继续与相关业务或 IT 团队确认 CPQ 当前可提供的报价单查询接口能力。
  • 明确 CPQ 是否支持按产品名称、物料编码或销售型号查询报价单列表。
  • 确认 CPQ 接口是否能返回 seller、审批状态、申请时间、报价单号等关键字段。
  • 评估将 SupplyRiskQueryMapper 替换为 CPQ API 调用的代码改造范围。
  • 根据 CPQ 接口能力重新调整供应风险、产品退市、已下单风险三类链路的数据来源。
  • 继续完善性能评估方案,避免上线后出现大表模糊查询导致接口耗时过长的问题。
  • 与前端确认后续是否需要移除 orderId 输入框,并增加 warningType 与产品型号输入的适配交互。
  • 保留当前本地实现作为逻辑验证版本,待 CPQ 数据源确认后进行二次改造和联调。

六、总结#

今天主要围绕供应风险预警推送完善进行了实际开发实施。基于前一天确定的开发计划,我完成了 SCM 查询 Mapper、新的 warningType 推送路由、seller 解析、产品型号拆分、通知创建和旧逻辑替换等后端改造,并通过本地测试验证了核心功能链路。测试过程中也发现了两个重要问题:一是基于 LIKE '%keyword%' 的大表查询存在性能压力,二是生产环境中的 fcst_price_check_order 报价单同步表已经停用。整体来看,今天完成了预警精准推送新逻辑的代码验证和实现沉淀,同时也明确了后续真正上线前必须依赖 CPQ 接口补齐报价单数据源的问题。

2026-06-10|供应风险预警推送完善实现与验证
https://jupiter-ws.cn/posts/internship/实习日报-2026-06-10/
作者
Jupiter
发布于
2026-06-10
许可协议
CC BY-NC-SA 4.0