Files
FTC25009/docs/superpowers/specs/2026-07-16-dense-outbound-relocation-dispatch-design.md

15 KiB
Raw Blame History

密集库出库补偿、移库与指定通道作业设计

1. 目标

在不改变现有入库流程和非密集库出库规则的前提下,完成以下能力:

  1. 出库作业下发 WCS 失败后自动补偿,最多自动重试 5 次,耗尽后支持人工下发。
  2. 所有 03 密集库出库与移库作业在下发前都必须是所在通道当前最外侧作业。
  3. 指定托盘和指定货位出库遇到遮挡时,自动生成 in_or_out=23 的移库作业。
  4. KPI 货位平面图支持按通道、数量和目标通道生成同层移库作业。
  5. 新增指定通道出库菜单,按通道组查看库存并按端头托盘数量生成出库作业。
  6. 入库、普通出库、指定货位/通道出库和移库使用不同的 WCS 接口配置。

2. 现状约束

  • 后端为 RuoYi Maven 多模块项目,出库作业与入库作业共用 mydo_job、mydo_job_detail。
  • 作业归档过程存在 INSERT ... SELECT *,直接给 mydo_job 增加字段会同步影响活动表、归档表和多个存储过程。
  • 03 仓的一个通道由同一排、同一层、同一通道带的 group_coding 标识。
  • bas_cargo_area_config.direction_type 是入库由深到浅的货位选择方向:方向 1 为列号从小到大,方向 2 为列号从大到小。
  • 当前出库代码错误复用了 sendPutawayTask 配置键;本设计改为按作业类型路由。
  • 当前 WCS 模拟开关默认开启,真实联调时必须显式关闭。

3. 总体架构

采用“业务作业 + WCS 下发记录”的 Outbox 结构:

  • mydo_job 继续保存业务作业,不增加补偿字段。
  • 新表 wcs_job_dispatch 与作业一一关联,保存下发状态、重试次数、错误、时间和并发版本。
  • OutboundDispatchService 是所有出库、指定货位、指定通道和移库作业下发 WCS 的唯一入口。
  • DenseLaneService 负责密集库通道顺序、遮挡托盘、最外侧资格和移库目标货位选择。
  • RelocationJobService 负责自动/人工移库作业生成和 WCS 完成后的库存搬移。
  • Quartz 每分钟调用 WcsOutboundRetryTask.retryFailedJobs() 执行自动补偿。

所有入口统一调用同一套下发资格检查,前端按钮、定时重试和分配后即时下发不能绕过密集库最外侧规则。

4. WCS 下发记录

新增表 wcs_job_dispatch:

字段 类型 说明
job_id nvarchar(255) PK 对应作业 ID
dispatch_status nvarchar(20) PENDING、SENDING、BLOCKED、RETRY_WAIT、SUCCESS、EXHAUSTED
auto_retry_count int 已执行的自动重试次数,范围 0 至 5
manual_retry_count int 人工下发次数
last_error nvarchar(1000) 最后一次失败或等待原因
last_attempt_time datetime2 最后一次实际调用 WCS 时间
next_retry_time datetime2 下次允许自动重试时间
success_time datetime2 下发成功时间
version_no int 并发抢占版本
create_time datetime2 创建时间
update_time datetime2 更新时间

初次下发失败不计入自动重试次数,状态设为 RETRY_WAIT、auto_retry_count=0。定时任务每调用一次前递增自动重试次数,失败达到 5 次后设为 EXHAUSTED。人工下发只递增 manual_retry_count,不重置自动重试次数,也不会重新进入自动队列。

密集库作业因不是当前最外侧而未调用 WCS 时,不计失败、不增加重试次数,记录统一设为 BLOCKED 并写入等待原因。外侧作业完成后立即唤醒同通道 BLOCKED 记录;定时任务每分钟复查一次 BLOCKED 记录作为异常恢复兜底。

通过原子状态更新把记录抢占为 SENDING,防止定时任务、人工按钮和业务线程并发重复下发。超过发送超时时间仍为 SENDING 的记录允许重新进入补偿流程。WCS 以 taskNo 作为幂等键;重复报文必须返回同一任务的成功确认。

5. 下发状态流转

5.1 分配后即时下发

  1. 出库分配或作业生成事务提交。
  2. 创建 PENDING 下发记录。
  3. 调用统一下发服务。
  4. 资格不满足:转为 BLOCKED,业务接口返回作业已生成、等待外侧作业完成。
  5. WCS 调用失败:记录 RETRY_WAIT,业务接口返回作业已生成、WCS 下发失败并进入补偿队列。
  6. WCS 调用成功:记录 SUCCESS,作业状态改为 3,执行阶段改为 1,写入开始时间。

分配成功后不因 WCS 网络失败回滚库存预占和作业生成,避免操作员重复分配。数据库分配失败仍按现有事务回滚。

5.2 自动重试

  • Quartz 每分钟扫描 RETRY_WAIT 且 auto_retry_count < 5、next_retry_time <= 当前时间 的记录,同时复查 BLOCKED 作业是否已经成为最外侧。
  • 每批按创建时间处理,单批数量可配置,默认 100。
  • 重新执行作业存在性、作业状态、密集库最外侧和 WCS 路由检查。
  • 网络或业务失败采用固定 1 分钟间隔;第 5 次失败转为 EXHAUSTED。
  • BLOCKED 复查和最外侧资格不满足都不消耗重试次数。

5.3 人工下发

  • 出库作业管理对 PENDING、RETRY_WAIT、EXHAUSTED 的未完成作业显示“手动下发 WCS”。
  • 操作前弹出确认框,展示自动重试次数和最后错误。
  • 人工下发仍执行密集库最外侧校验。
  • 失败后保持原自动状态或 EXHAUSTED,更新错误和人工次数;成功后转为 SUCCESS。

6. 密集库最外侧规则

仅仓库 03 且货位存在非空 group_coding 时应用密集库规则。

  • 同通道范围:warehouse_id + group_coding,group_coding 已包含排和层。
  • 方向 1:入库从小列到大列,当前最外侧为所有占用/预占货位中的最大列。
  • 方向 2:入库从大列到小列,当前最外侧为所有占用/预占货位中的最小列。
  • 方向 3:按距离两侧边界较近者优先,同距离取较小列。
  • 占用范围包括状态 2(满)、3(入库分配)、4(出库/移库分配)且托盘码非空的货位。

资格检查以事务中的实时货位数据为准,不能使用页面缓存。若同一最外侧托盘已经存在状态 2/3 的活动作业,只允许该作业继续,其他作业等待。

7. 遮挡处理与自动移库

7.1 触发范围

  • 出库单分配明确指定库存明细、库存主记录或托盘时。
  • 指定货位出库选择 03 仓密集库货位时。
  • 指定托盘前存在其他占用托盘时。

7.2 遮挡托盘判定

按第 6 节的出库顺序,位于目标托盘外侧的占用托盘均为遮挡托盘。

  • 遮挡托盘已有活动出库作业时,不再生成移库作业;该出库作业自然成为前置动作。
  • 遮挡托盘没有活动出库/移库作业时,按从外到内顺序生成移库作业。
  • 目标出库作业可以同时生成,但只有所有外侧货位释放后才具备下发资格。

7.3 自动移库目标

目标货位必须满足:

  • 同仓库、同层、不同 group_coding。
  • 状态为 1、未锁定、无托盘码。
  • 符合托盘类型允许仓库和货位类型规则。
  • 符合原通道的存储模式、项目号或物料相容规则。
  • 不得被其他活动作业预占。

候选通道优先沿用现有入库规则:优先已有相容库存的通道,再按占用数量和通道编码选择;通道内按入库方向选择最深可用货位。生成作业后将源货位置为 4,目标货位置为 3 并预留托盘码。

8. 移库作业

  • in_or_out=23,任务号调用 util_serial_task '23'。
  • 主作业的 cargo_space_id 为源货位,target_cargo_space_id 为目标货位。
  • 每个托盘生成一个移库主作业;按库存明细生成对应 mydo_job_detail,保留库存、批次、项目号和数量追溯。
  • 移库作业使用独立 WCS 路由,不进入 PDA 出库确认列表。

WCS 完成移库回调后,在一个数据库事务内:

  1. 锁定移库作业、源货位、目标货位和托盘库存。
  2. 校验作业类型为 23、作业已下发、源目标仍与作业一致。
  3. 将该托盘所有 bas_stock.cargo_space_id 更新为目标货位。
  4. 源货位置为 1 并清空托盘码,目标货位置为 2 并保留托盘码。
  5. 作业及明细归档并从活动表删除。
  6. 事务提交后触发同源通道下一条等待作业的资格检查和即时下发。

重复完成回调通过活动/归档作业查询实现幂等,已完成时返回成功。

9. KPI 货位平面图指定移库

仅在 03 密集库视图显示“指定移库”命令。弹窗包含:

  • 当前层,只读。
  • 源通道选择,只列出当前层有满货位的通道。
  • 移库托盘数量,范围 1 至源通道当前可移动托盘数。
  • 目标通道选择,只列出当前层具有足够相容空位的其他通道。
  • 外侧托盘预览,展示托盘码、源货位、库存明细和总数量。

提交时后端重新锁定并验证通道、层、数量、库存与目标容量,按外到内选择源托盘并生成移库作业。页面数据只用于预览,不作为作业生成依据。

10. 指定货位出库

现有非密集库逻辑保持不变。03 密集库指定货位出库调整为:

  1. 锁定目标货位和通道。
  2. 计算外侧遮挡托盘。
  3. 为没有活动出库作业的遮挡托盘生成移库作业。
  4. 生成目标托盘的指定货位出库作业及下发记录。
  5. 先尝试下发当前最外侧移库/出库作业;目标作业等待通道逐步清空。

11. 指定通道出库

在出库管理下新增“指定通道出库”菜单和权限:

  • out:denseLaneOutbound:list
  • out:denseLaneOutbound:preview
  • out:denseLaneOutbound:generate

列表仅查询 03 仓 group_coding 非空且至少存在一个状态 2 满货位的通道,展示:

  • 通道组编码、货区、排、层和方向。
  • 满托盘数量、可出库托盘数量、库存总数量。
  • 聚合库存摘要和可展开库存明细。
  • 当前最外侧托盘及货位。

生成弹窗要求选择整托数量和适配出库口。后端按当前外侧顺序选择前 N 个未被活动作业占用的托盘,返回预览供确认,确认后每托生成一个指定出库作业和完整作业明细。任何托盘状态变化都会使旧预览失效,提交时重新校验并返回明确冲突信息。

12. WCS 路由

配置增加独立键并允许通过环境变量覆盖:

external:
  systems:
    WCS:
      apis:
        sendPutawayTask: ${WCS_PUTAWAY_PATH:/wcs/api/receiveWmsJob}
        sendRetrieveTask: ${WCS_OUTBOUND_PATH:/wcs/api/receiveWmsOutJob}
        sendLocationOutboundTask: ${WCS_LOCATION_OUTBOUND_PATH:/wcs/api/receiveWmsLocationOutJob}
        sendRelocationTask: ${WCS_RELOCATION_PATH:/wcs/api/receiveWmsMoveJob}

路由规则:

  • in_or_out < 20:sendPutawayTask。
  • in_or_out = 20:sendLocationOutboundTask,覆盖指定货位和指定通道整托出库。
  • in_or_out = 23:sendRelocationTask。
  • 其他 in_or_out >= 20:sendRetrieveTask。

所有接口继续按作业所属仓库解析独立 WCS 根地址。

13. UI 设计

沿用现有 Vue 2、Element UI 和 RuoYi 页面密度:

  • 出库作业列表增加“WCS 下发状态”“自动重试”“最后错误”列;错误使用 tooltip,避免撑高表格。
  • “手动下发 WCS”使用发送图标和确认对话框,仅对允许状态显示。
  • KPI 平面图在密集库工具栏增加移库命令,使用紧凑表单弹窗,不改变平面图颜色体系。
  • 指定通道出库采用筛选栏、通道表格和单层生成弹窗;库存明细使用表格展开行,不嵌套装饰卡片。

14. 数据库迁移

新增一份可重复执行的 SQL Server 迁移脚本,包含:

  • 创建 wcs_job_dispatch、状态/重试索引和字段说明。
  • 确认 bas_task_no 存在 ID 23,存在则保留当前序号,不存在则补充移库类型。
  • 新增指定通道出库菜单、按钮权限和角色授权兼容处理。
  • 新增 Quartz 任务记录,调用 wcsOutboundRetryTask.retryFailedJobs,Cron 为每分钟一次,禁止并发。
  • 为密集库通道、活动作业和下发扫描补充必要索引,创建前检查同名索引。

迁移不修改或删除现有业务数据,可重复执行。

15. 错误处理

  • WCS 网络失败、超时、非成功响应和报文序列化失败均写入下发记录。
  • 最外侧不满足、前置作业未完成和目标货位状态变化属于等待/并发冲突,不消耗自动重试次数。
  • 自动移库目标不足时,原出库分配整体失败,不生成部分移库作业。
  • 人工指定移库目标容量或相容性不足时,整个请求回滚。
  • 移库完成时源目标或库存不一致,事务回滚并返回明确错误,不做部分库存搬移。
  • 菜单生成作业时预览已过期,返回刷新提示,不自动替换为其他托盘。

16. 测试与验收

16.1 后端单元与 Mapper 测试

  • 首次失败进入补偿队列且自动次数为 0。
  • 自动重试恰好最多执行 5 次,第 5 次失败后耗尽。
  • 人工下发超过 5 次仍可调用,但不会恢复自动队列。
  • 调度并发抢占只有一个调用者成功。
  • 非最外侧作业不调用 WCS且不增加重试次数。
  • 方向 1、方向 2 的最外侧和遮挡集合正确。
  • 指定托盘/货位遮挡时按外到内生成类型 23 作业。
  • 自动目标同层、不同通道、相容且按入库规则选深位。
  • 移库完成原子更新库存、源目标货位并归档。
  • 指定通道预览与生成只选择端头 N 个托盘。
  • 20、23 和普通出库分别命中正确 WCS 配置键。

16.2 前端验证

  • 出库作业列表正确显示状态、次数、错误和人工按钮权限。
  • KPI 指定移库只能选择同层目标通道,数量和容量校验提示明确。
  • 指定通道出库列表、展开明细、预览数量和生成确认可用。
  • 生产构建通过,桌面和常用窄屏下表格、弹窗无文字遮挡。

16.3 集成场景

  1. 构造 WCS 连续失败,验证初次调用加 5 次自动重试后耗尽。
  2. 人工恢复下发,验证成功状态和作业状态更新。
  3. 在方向 1 和方向 2 通道各构造三托遮挡,验证下发顺序为外到内。
  4. 指定最内托盘出库,验证先生成并完成两个移库作业,再下发目标出库。
  5. KPI 指定跨通道同层移库,验证库存和货位一致。
  6. 指定通道出库 N 托,验证只选择端头 N 托及其完整库存。
  7. 验证非 03 仓原有自动、手动和指定货位出库不受影响。

17. 需求覆盖

原需求 设计章节
失败标记、5 次重试、定时器、人工下发、最外侧校验 4、5、6
指定托盘遮挡自动移库,类型 23 7、8
KPI 平面图指定同层移库 9
出库 WCS 地址区分 12
指定货位出库遮挡移库 10
指定通道出库菜单与端头 N 托 11