【WMS学习笔记系列】03-功能模块设计

功能模块设计

3.1 模块总览

WMS 功能模块
├── 基础数据管理      → wms-core
├── 入库管理          → wms-inbound
├── 出库管理          → wms-outbound
├── 库存管理          → wms-inventory
├── 盘点管理          → wms-count
└── 报表看板          → wms-report

3.2 入库管理流程

3.2.1 整体状态机


ASN 创建 → 已通知 → 收货中 → 收货完成 → 上架中 → 上架完成
                ↓         ↓
              已取消     异常

3.2.2 详细流程

Step 1: ASN 创建
│  上游(采购系统/ERP)推送 ASN 数据
│  包含:ASN 单号、供应商、预计到货时间、商品明细
│  状态:已通知
│
Step 2: 收货
│  仓库管理员扫描 ASN 单号
│  逐 SKU 扫描条码 / 输入实收数量
│  系统校验:实收 vs 预计
│  ├── 一致 → 收货完成
│  ├── 少于 → 标记差异,部分收货
│  └── 多于 → 标记异常(无单收货审批)
│
Step 3: 上架
│  系统根据上架策略推荐库位
│  管理员扫描库位码确认上架
│  库存数量 +N,库位状态更新
│  状态:上架完成

3.2.3 上架策略伪代码

public List<Location> recommendLocations(Sku sku, int qty) {
    // 1. 查询该 SKU 已有库存的库位
    List<Location> existingLocations = inventoryMapper
        .findLocationsBySkuId(sku.getId());

    if (!existingLocations.isEmpty()) {
        return existingLocations.stream()
            .filter(loc -> loc.getAvailableCapacity() >= qty)
            .sorted(Comparator.comparingInt(Location::getAvailableCapacity))
            .limit(3)
            .collect(Collectors.toList());
    }

    // 2. 按 ABC 分类 + 容量筛选空库位
    String abcClass = sku.getAbcClass(); // A / B / C
    return locationMapper.findAvailableByAbcClass(abcClass, qty, 3);
}

3.3 出库管理流程

3.3.1 整体状态机


订单接收 → 波次生成 → 分配库存 → 拣货中 → 拣货完成 → 复核中 → 复核完成 → 已发货
             ↓           ↓          ↓         ↓
           已取消      缺货异常    缺货标记    差异退回

3.3.2 详细流程

Step 1: 订单接收
│  OMS 推送出库订单
│  含:订单号、客户、商品明细、期望发货时间、承运商
│
Step 2: 波次生成
│  根据波次策略将多个订单合并为波次
│  波次 = 拣货任务的基本单位
│
Step 3: 库存分配
│  按 FIFO / 批次优先规则分配库存
│  锁定库存(预占,防止被其他订单抢走)
│  生成拣货任务清单
│
Step 4: 拣货
│  拣货员 PDA 接收任务
│  系统按库位排序优化拣货路径
│  扫描库位 → 扫描商品 → 确认数量
│
Step 5: 复核
│  扫描订单号 → 逐件扫描商品条码
│  重量校验:实际重量 vs 理论重量
│  差异处理
│
Step 6: 打包发货
│  打印面单、装箱清单
│  称重、测量体积
│  交接承运商 → 扣减库存

3.3.3 拣货路径优化

仓库库位布局示例(数字为库位编号):
┌──────────────────────────────┐
│  01  02  03  04  │  21 22 23 │ ← A 区(快周转)
│  05  06  07  08  │  24 25 26 │
│─────────────────────────────│
│  09  10  11  12  │  27 28 29 │ ← B 区(中周转)
│  13  14  15  16  │  30 31 32 │
│─────────────────────────────│
│  17  18  19  20  │  33 34 35 │ ← C 区(慢周转)
└──────────────────────────────┘
                    ↑
              复核区 / 发货区

优化后路径:从靠近发货区的库位开始,
           由近到远排列拣货任务

示例:需要拣 03, 18, 25 三个库位
原始顺序:03 → 18 → 25 (S型路径,效率低)
优化顺序:25 → 03 → 18 (由近及远)

3.3.4 播种式 vs 摘果式拣货

方式描述适用场景
摘果式一个拣货员完成一个订单的所有商品订单少、单品多
播种式先汇总多个订单的总需求量,统一拣货后再按订单分播订单多、SKU 重合度高

3.4 库存管理

3.4.1 库存维度模型

库存 = f(仓库, SKU, 库位, 批次, 状态, 货主)

查询示例:
"查询仓库1中 SKU-1001 在所有库位的可用库存"
→ SUM(quantity) WHERE warehouse_id=1 AND sku_id=1001 
  AND status='AVAILABLE'

3.4.2 库存状态

状态含义是否可分配
AVAILABLE可用
LOCKED锁定(已被订单预占)
FROZEN冻结(质检中)
DAMAGED残次
EXPIRED过期

3.4.3 库存扣减时序

出库订单分配库存的时序(防止并发超扣):

┌────────────────┐
│ 开启事务 (BEGIN) │
└───────┬────────┘
        ▼
┌───────────────────────────────────┐
│ SELECT * FROM inventory            │
│ WHERE sku_id = ?                   │
│   AND status = 'AVAILABLE'         │
│   AND quantity > 0                 │
│ ORDER BY production_date ASC       │  ← FIFO: 先过期先出
│ FOR UPDATE                         │  ← 行锁
└───────┬───────────────────────────┘
        ▼
┌────────────────────────┐
│ 计算扣减量,逐行扣减      │
│ 若 quantity >= need:   │
│   扣 need,完成          │
│ 若 quantity < need:    │
│   全扣,继续下一行       │
└───────┬────────────────┘
        ▼
┌────────────────────┐
│ 更新库存行           │
│ 插入库存变更流水      │
└───────┬────────────┘
        ▼
┌──────────────────┐
│ 提交事务 (COMMIT) │
└──────────────────┘

3.4.4 安全库存预警

-- 低库存预警:当前可用库存 < 安全库存阈值
SELECT 
    s.sku_code,
    s.sku_name,
    s.safety_stock,
    COALESCE(SUM(i.quantity), 0) AS current_stock
FROM sku s
LEFT JOIN inventory i 
    ON s.id = i.sku_id AND i.status = 'AVAILABLE'
GROUP BY s.id
HAVING current_stock < s.safety_stock;

3.5 盘点管理

3.5.1 盘点类型

类型说明频率
动态盘点每日出入库结束后对变动库位复盘每日
循环盘点按库区轮转,每天盘一个区域按计划
全面盘点全仓库所有库位盘点月度/季度
随机抽盘随机抽取部分 SKU 或库位盘点按需

3.5.2 盘点流程

Step 1: 创建盘点计划
│  选择盘点类型、范围(仓库/库区/SKU)
│  选择盘点方式:明盘(显示系统库存)/ 盲盘(不显示)
│
Step 2: 生成盘点任务
│  按库位/库区拆分任务
│  分配盘点人员
│  库位冻结(可选,盘点期间禁止出入库操作)
│
Step 3: 执行盘点
│  盘点员扫描库位码
│  逐 SKU 扫描条码,录入实际数量
│  系统对比账面数量
│
Step 4: 差异处理
│  无差异 → 盘点完成
│  有差异 → 复盘(二次盘点)
│  复盘仍有差异 → 生成差异报告 → 主管审核
│
Step 5: 库存调整
│  审核通过后调整库存
│  生成盘盈/盘亏单据
│  记录操作日志

3.5.3 盘点锁定策略

盘点锁库策略(针对部分盘点):
┌──────────────────────────────────────┐
│ 临时表:count_lock                    │
│ ┌──────────┬──────────┬────────────┐ │
│ │ location │ lock_type │ lock_time   │ │
│ ├──────────┼──────────┼────────────┤ │
│ │ A-01-01  │ COUNTING  │ 2026-07-30 │ │
│ │ A-01-02  │ COUNTING  │ 2026-07-30 │ │
│ └──────────┴──────────┴────────────┘ │
│                                      │
│ 出入库时检查:若库位在 count_lock 中  │
│ 且 lock_type=COUNTING,则拒绝操作     │
└──────────────────────────────────────┘

3.6 库位管理

3.6.1 库位编码规则

推荐编码格式:仓库-库区-排-列-层

示例:WH01-A-03-05-02

WH01  仓库编号
A     库区(A区快周转 / B区中周转 / C区慢周转)
03    第 3 排货架
05    第 5 列
02    第 2 层

3.6.2 库位属性

属性说明
库位编码唯一标识
库位类型存储位 / 拣货位 / 暂存位 / 退货位 / 残次位
容量最大存放数量 / 最大体积 / 最大重量
状态空闲 / 占用 / 冻结 / 禁用
ABC 分类对应的周转率分类

3.7 事件驱动解耦

业务模块之间通过 Spring Event / RabbitMQ 解耦:

入库完成事件
  ├── → 库存模块:更新库存
  ├── → 报表模块:更新入库统计
  └── → 通知模块:发送入库通知

出库完成事件
  ├── → 库存模块:扣减库存
  ├── → 报表模块:更新出库统计
  └── → OMS:回传发货状态

盘点调整事件
  ├── → 库存模块:调整库存
  └── → 审计模块:记录调整日志
// 事件定义
public class InboundCompletedEvent extends ApplicationEvent {
    private final Long asnId;
    private final List<InboundDetail> details;
    // ...
}

// 事件发布
@Transactional
public void completeInbound(Long asnId) {
    // 业务处理...
    eventPublisher.publishEvent(new InboundCompletedEvent(this, asnId, details));
}

// 事件监听
@Component
public class InventoryEventListener {
    @EventListener
    @Transactional
    public void handleInboundCompleted(InboundCompletedEvent event) {
        // 更新库存
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值