282 lines
15 KiB
Markdown
282 lines
15 KiB
Markdown
# 密集库出库补偿、移库与指定通道作业设计
|
||
|
||
## 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 路由
|
||
|
||
配置增加独立键并允许通过环境变量覆盖:
|
||
|
||
```yaml
|
||
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 |
|