WMS与OMS集成——打通订单履约的关键链路

引言:WMS与OMS的关系 OMS是大脑,WMS是手脚: OMS负责订单决策:接单、拆单、分仓 WMS负责实物执行:拣货、打包、发货 集成的核心目标: 指令准确传递:OMS的出库指令准确下发到WMS 库存实时同步:WMS的实物库存实时同步到OMS 状态及时回传:WMS的执行状态及时回传OMS 一、集成架构 1.1 系统边界 ┌─────────────────────────────────────────────────────────────┐ │ OMS │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │订单管理 │ │库存预占 │ │履约路由 │ │状态跟踪 │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ └───────┼───────────┼───────────┼───────────┼─────────────────┘ │ │ │ │ │ ┌──────┴───────────┴───────────┴──────┐ │ │ 消息队列/API │ │ └──────┬───────────┬───────────┬──────┘ │ │ │ │ ┌───────┼───────────┼───────────┼───────────┼─────────────────┐ │ ▼ ▼ ▼ ▼ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │出库管理 │ │库存管理 │ │拣货管理 │ │发货管理 │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ WMS │ └─────────────────────────────────────────────────────────────┘ 1.2 数据流向 数据 方向 说明 出库指令 OMS → WMS 订单履约指令 可售库存 WMS → OMS 库存同步 出库状态 WMS → OMS 拣货、发货状态 库存变动 WMS → OMS 入库、盘点等 二、出库指令下发 2.1 出库单数据结构 /** * OMS下发给WMS的出库指令 */ public class OutboundCommand { private String commandId; // 指令ID private String orderNo; // OMS订单号 private String warehouseId; // 仓库ID // 收货信息 private String consignee; // 收货人 private String phone; // 电话 private String province; // 省 private String city; // 市 private String district; // 区 private String address; // 详细地址 // 物流信息 private String carrierCode; // 承运商编码 private String serviceType; // 服务类型 // 时效要求 private Integer priority; // 优先级 private LocalDateTime deadline; // 截止时间 // 商品明细 private List<OutboundItem> items; // 扩展信息 private Map<String, String> extInfo; } public class OutboundItem { private String skuId; // SKU编码 private String skuName; // SKU名称 private Integer quantity; // 数量 private String barcode; // 条码 } 2.2 指令下发服务 @Service public class OutboundCommandService { @Autowired private RocketMQTemplate rocketMQTemplate; /** * OMS调用:下发出库指令 */ public void sendOutboundCommand(OutboundCommand command) { // 1. 参数校验 validateCommand(command); // 2. 幂等检查 if (commandRepository.existsByCommandId(command.getCommandId())) { log.warn("重复指令: {}", command.getCommandId()); return; } // 3. 保存指令记录 OutboundCommandRecord record = new OutboundCommandRecord(); record.setCommandId(command.getCommandId()); record.setOrderNo(command.getOrderNo()); record.setWarehouseId(command.getWarehouseId()); record.setStatus(CommandStatus.SENT); record.setContent(JSON.toJSONString(command)); record.setCreatedAt(LocalDateTime.now()); commandRepository.save(record); // 4. 发送消息到WMS String topic = "WMS_OUTBOUND_COMMAND_" + command.getWarehouseId(); rocketMQTemplate.syncSend(topic, command); log.info("出库指令已下发: {}", command.getCommandId()); } } 2.3 WMS接收处理 @Service @RocketMQMessageListener( topic = "WMS_OUTBOUND_COMMAND_${warehouse.id}", consumerGroup = "wms-outbound-consumer" ) public class OutboundCommandConsumer implements RocketMQListener<OutboundCommand> { @Override public void onMessage(OutboundCommand command) { try { // 1. 幂等检查 if (outboundOrderRepository.existsByOmsOrderNo(command.getOrderNo())) { log.warn("订单已存在: {}", command.getOrderNo()); return; } // 2. 创建WMS出库单 OutboundOrder order = createOutboundOrder(command); // 3. 校验库存 boolean stockAvailable = checkStock(order); if (!stockAvailable) { // 库存不足,回传异常 sendStockShortageCallback(command, order); return; } // 4. 锁定库存 lockStock(order); // 5. 回传接收成功 sendReceiveCallback(command.getCommandId(), "SUCCESS"); } catch (Exception e) { log.error("处理出库指令失败: {}", command.getCommandId(), e); sendReceiveCallback(command.getCommandId(), "FAIL", e.getMessage()); } } private OutboundOrder createOutboundOrder(OutboundCommand command) { OutboundOrder order = new OutboundOrder(); order.setOutboundNo(generateOutboundNo()); order.setOmsOrderNo(command.getOrderNo()); order.setWarehouseId(command.getWarehouseId()); order.setConsignee(command.getConsignee()); order.setPhone(command.getPhone()); order.setAddress(buildFullAddress(command)); order.setCarrierCode(command.getCarrierCode()); order.setPriority(command.getPriority()); order.setDeadline(command.getDeadline()); order.setStatus(OutboundStatus.CREATED); outboundOrderRepository.save(order); // 保存明细 for (OutboundItem item : command.getItems()) { OutboundOrderItem orderItem = new OutboundOrderItem(); orderItem.setOutboundNo(order.getOutboundNo()); orderItem.setSkuId(item.getSkuId()); orderItem.setQuantity(item.getQuantity()); outboundItemRepository.save(orderItem); } return order; } } 三、库存同步 3.1 库存同步策略 策略 说明 适用场景 实时同步 每次变动立即同步 库存紧张、高并发 定时同步 定时批量同步 库存充足 增量同步 只同步变化部分 数据量大 全量同步 定期全量覆盖 数据校准 3.2 实时库存同步 @Service public class InventorySyncService { /** * 库存变动时触发同步 */ @EventListener public void onInventoryChange(InventoryChangeEvent event) { // 计算可售库存 int availableQty = calculateAvailableQty( event.getWarehouseId(), event.getSkuId() ); // 发送同步消息 InventorySyncMessage message = new InventorySyncMessage(); message.setWarehouseId(event.getWarehouseId()); message.setSkuId(event.getSkuId()); message.setAvailableQty(availableQty); message.setChangeType(event.getChangeType()); message.setChangeQty(event.getChangeQty()); message.setTimestamp(LocalDateTime.now()); rocketMQTemplate.asyncSend("OMS_INVENTORY_SYNC", message, new SendCallback() { @Override public void onSuccess(SendResult sendResult) { log.info("库存同步成功: {} {}", event.getSkuId(), availableQty); } @Override public void onException(Throwable e) { log.error("库存同步失败: {}", event.getSkuId(), e); // 加入重试队列 retrySyncQueue.add(message); } }); } /** * 计算可售库存 * 可售 = 实物库存 - 锁定库存 - 安全库存 */ private int calculateAvailableQty(String warehouseId, String skuId) { // 查询实物库存 int physicalQty = inventoryRepository.sumQuantity(warehouseId, skuId); // 查询锁定库存 int lockedQty = inventoryRepository.sumLockedQty(warehouseId, skuId); // 查询安全库存 int safetyStock = skuService.getSafetyStock(skuId); return Math.max(0, physicalQty - lockedQty - safetyStock); } } 3.3 OMS接收库存同步 @Service @RocketMQMessageListener( topic = "OMS_INVENTORY_SYNC", consumerGroup = "oms-inventory-consumer" ) public class InventorySyncConsumer implements RocketMQListener<InventorySyncMessage> { @Override public void onMessage(InventorySyncMessage message) { // 1. 更新OMS库存 OmsInventory inventory = omsInventoryRepository .findByWarehouseAndSku(message.getWarehouseId(), message.getSkuId()); if (inventory == null) { inventory = new OmsInventory(); inventory.setWarehouseId(message.getWarehouseId()); inventory.setSkuId(message.getSkuId()); } inventory.setAvailableQty(message.getAvailableQty()); inventory.setLastSyncTime(message.getTimestamp()); omsInventoryRepository.save(inventory); // 2. 更新渠道库存(如果需要) channelInventoryService.syncToChannels(message.getSkuId()); // 3. 检查库存预警 checkInventoryAlert(message); } } 3.4 定时全量同步 @Service public class FullInventorySyncService { /** * 每天凌晨全量同步库存 */ @Scheduled(cron = "0 0 2 * * ?") public void fullSync() { log.info("开始全量库存同步"); List<String> warehouses = warehouseService.getAllActiveWarehouses(); for (String warehouseId : warehouses) { // 获取WMS所有库存 List<InventorySummary> wmsInventories = wmsClient.getAllInventory(warehouseId); // 批量同步到OMS List<InventorySyncMessage> messages = wmsInventories.stream() .map(inv -> { InventorySyncMessage msg = new InventorySyncMessage(); msg.setWarehouseId(warehouseId); msg.setSkuId(inv.getSkuId()); msg.setAvailableQty(inv.getAvailableQty()); msg.setChangeType("FULL_SYNC"); return msg; }) .collect(Collectors.toList()); // 批量发送 rocketMQTemplate.syncSend("OMS_INVENTORY_SYNC_BATCH", messages); } log.info("全量库存同步完成"); } } 四、状态回传 4.1 状态流转 OMS订单状态: 待发货 ──> 拣货中 ──> 已发货 ──> 已签收 │ │ │ │ WMS状态回传: │ │ │ │ ▼ ▼ ▼ ▼ 接收成功 开始拣货 发货完成 物流回传 4.2 状态回传消息 /** * WMS回传给OMS的状态消息 */ public class OutboundStatusCallback { private String callbackId; // 回传ID private String omsOrderNo; // OMS订单号 private String wmsOutboundNo; // WMS出库单号 private String status; // 状态 private LocalDateTime statusTime; // 状态时间 // 发货信息(发货状态时填写) private String trackingNo; // 物流单号 private String carrierCode; // 承运商 private Integer packageCount; // 包裹数 private BigDecimal weight; // 重量 // 异常信息 private String errorCode; // 错误码 private String errorMessage; // 错误信息 } 4.3 状态回传服务 @Service public class StatusCallbackService { /** * 拣货开始回传 */ public void callbackPickStart(OutboundOrder order) { OutboundStatusCallback callback = new OutboundStatusCallback(); callback.setCallbackId(generateCallbackId()); callback.setOmsOrderNo(order.getOmsOrderNo()); callback.setWmsOutboundNo(order.getOutboundNo()); callback.setStatus("PICKING"); callback.setStatusTime(LocalDateTime.now()); sendCallback(callback); } /** * 发货完成回传 */ public void callbackShipped(OutboundOrder order, ShipmentInfo shipment) { OutboundStatusCallback callback = new OutboundStatusCallback(); callback.setCallbackId(generateCallbackId()); callback.setOmsOrderNo(order.getOmsOrderNo()); callback.setWmsOutboundNo(order.getOutboundNo()); callback.setStatus("SHIPPED"); callback.setStatusTime(LocalDateTime.now()); callback.setTrackingNo(shipment.getTrackingNo()); callback.setCarrierCode(shipment.getCarrierCode()); callback.setPackageCount(shipment.getPackageCount()); callback.setWeight(shipment.getWeight()); sendCallback(callback); } /** * 异常回传 */ public void callbackException(OutboundOrder order, String errorCode, String errorMessage) { OutboundStatusCallback callback = new OutboundStatusCallback(); callback.setCallbackId(generateCallbackId()); callback.setOmsOrderNo(order.getOmsOrderNo()); callback.setWmsOutboundNo(order.getOutboundNo()); callback.setStatus("EXCEPTION"); callback.setStatusTime(LocalDateTime.now()); callback.setErrorCode(errorCode); callback.setErrorMessage(errorMessage); sendCallback(callback); } private void sendCallback(OutboundStatusCallback callback) { // 保存回传记录 CallbackRecord record = new CallbackRecord(); record.setCallbackId(callback.getCallbackId()); record.setContent(JSON.toJSONString(callback)); record.setStatus(CallbackStatus.PENDING); callbackRepository.save(record); // 发送消息 rocketMQTemplate.asyncSend("OMS_STATUS_CALLBACK", callback, new SendCallback() { @Override public void onSuccess(SendResult sendResult) { record.setStatus(CallbackStatus.SUCCESS); callbackRepository.save(record); } @Override public void onException(Throwable e) { record.setStatus(CallbackStatus.FAIL); record.setErrorMessage(e.getMessage()); callbackRepository.save(record); // 加入重试队列 retryQueue.add(callback); } }); } } 4.4 OMS接收状态回传 @Service @RocketMQMessageListener( topic = "OMS_STATUS_CALLBACK", consumerGroup = "oms-callback-consumer" ) public class StatusCallbackConsumer implements RocketMQListener<OutboundStatusCallback> { @Override public void onMessage(OutboundStatusCallback callback) { // 1. 幂等检查 if (callbackRepository.existsByCallbackId(callback.getCallbackId())) { return; } // 2. 查找订单 Order order = orderRepository.findByOrderNo(callback.getOmsOrderNo()); if (order == null) { log.error("订单不存在: {}", callback.getOmsOrderNo()); return; } // 3. 更新订单状态 switch (callback.getStatus()) { case "PICKING": order.setStatus(OrderStatus.PICKING); order.setPickStartTime(callback.getStatusTime()); break; case "SHIPPED": order.setStatus(OrderStatus.SHIPPED); order.setShipTime(callback.getStatusTime()); order.setTrackingNo(callback.getTrackingNo()); order.setCarrierCode(callback.getCarrierCode()); // 释放库存预占 inventoryService.releaseReservation(order.getOrderNo()); break; case "EXCEPTION": order.setStatus(OrderStatus.EXCEPTION); order.setExceptionCode(callback.getErrorCode()); order.setExceptionMessage(callback.getErrorMessage()); // 触发异常处理流程 exceptionHandler.handle(order, callback); break; } orderRepository.save(order); // 4. 通知下游(如通知客户) notifyService.notifyOrderStatusChange(order); } } 五、异常处理 5.1 常见异常场景 异常 原因 处理方式 库存不足 WMS实际库存不够 重新分仓或取消 地址异常 地址无法配送 人工处理 SKU不存在 WMS没有该商品 检查主数据 超时未处理 WMS未及时处理 催促或转仓 5.2 异常处理服务 @Service public class IntegrationExceptionHandler { /** * 处理库存不足异常 */ public void handleStockShortage(Order order, OutboundStatusCallback callback) { // 1. 尝试重新分仓 String newWarehouse = fulfillmentRouter.findAlternativeWarehouse(order); if (newWarehouse != null) { // 取消原出库指令 wmsClient.cancelOutbound(order.getOrderNo(), order.getWarehouseId()); // 下发新出库指令 order.setWarehouseId(newWarehouse); outboundCommandService.sendOutboundCommand(buildCommand(order)); log.info("订单{}重新分仓到{}", order.getOrderNo(), newWarehouse); } else { // 无可用仓库,标记异常 order.setStatus(OrderStatus.STOCK_SHORTAGE); orderRepository.save(order); // 通知客服 alertService.notifyCustomerService(order, "库存不足,需人工处理"); } } /** * 处理超时未处理 */ @Scheduled(fixedRate = 300000) // 每5分钟检查 public void checkTimeoutOrders() { // 查找超时订单 LocalDateTime timeout = LocalDateTime.now().minusHours(4); List<Order> timeoutOrders = orderRepository .findByStatusAndCreatedBefore(OrderStatus.PENDING_SHIP, timeout); for (Order order : timeoutOrders) { // 查询WMS状态 OutboundOrder wmsOrder = wmsClient.getOutboundOrder(order.getOrderNo()); if (wmsOrder == null || wmsOrder.getStatus() == OutboundStatus.CREATED) { // WMS未处理,发送催促 alertService.notifyWarehouse(order.getWarehouseId(), "订单" + order.getOrderNo() + "超时未处理"); } } } } 六、接口设计 6.1 REST API接口 @RestController @RequestMapping("/api/wms") public class WmsIntegrationController { /** * OMS调用:下发出库指令 */ @PostMapping("/outbound/command") public Result<Void> sendOutboundCommand(@RequestBody OutboundCommand command) { outboundCommandService.sendOutboundCommand(command); return Result.success(); } /** * OMS调用:取消出库指令 */ @PostMapping("/outbound/cancel") public Result<Void> cancelOutbound(@RequestBody CancelRequest request) { wmsService.cancelOutbound(request.getOrderNo(), request.getReason()); return Result.success(); } /** * OMS调用:查询库存 */ @GetMapping("/inventory") public Result<InventoryVO> queryInventory( @RequestParam String warehouseId, @RequestParam String skuId) { InventoryVO inventory = inventoryService.queryInventory(warehouseId, skuId); return Result.success(inventory); } /** * WMS调用:状态回传 */ @PostMapping("/callback/status") public Result<Void> statusCallback(@RequestBody OutboundStatusCallback callback) { callbackService.handleCallback(callback); return Result.success(); } /** * WMS调用:库存同步 */ @PostMapping("/inventory/sync") public Result<Void> syncInventory(@RequestBody InventorySyncRequest request) { inventorySyncService.sync(request); return Result.success(); } } 6.2 接口幂等设计 @Aspect @Component public class IdempotentAspect { @Around("@annotation(idempotent)") public Object checkIdempotent(ProceedingJoinPoint point, Idempotent idempotent) throws Throwable { // 获取幂等键 String key = getIdempotentKey(point, idempotent); // 检查是否已处理 String result = redisTemplate.opsForValue().get(key); if (result != null) { log.info("重复请求,返回缓存结果: {}", key); return JSON.parseObject(result, point.getSignature().getDeclaringType()); } // 执行业务 Object response = point.proceed(); // 缓存结果 redisTemplate.opsForValue().set(key, JSON.toJSONString(response), idempotent.expireSeconds(), TimeUnit.SECONDS); return response; } } 七、监控与告警 7.1 集成监控指标 指标 说明 告警阈值 指令下发成功率 成功/总数 < 99% 库存同步延迟 同步耗时 > 5秒 状态回传延迟 回传耗时 > 10秒 消息积压数 队列积压 > 1000 7.2 监控实现 @Service public class IntegrationMonitorService { @Scheduled(fixedRate = 60000) public void monitor() { // 检查消息积压 long pendingCount = messageRepository.countPending(); if (pendingCount > 1000) { alertService.sendAlert("消息积压告警", "待处理消息数: " + pendingCount); } // 检查同步延迟 LocalDateTime lastSync = inventorySyncRepository.getLastSyncTime(); if (lastSync.isBefore(LocalDateTime.now().minusMinutes(5))) { alertService.sendAlert("库存同步延迟", "最后同步时间: " + lastSync); } // 检查失败率 long totalCount = callbackRepository.countByHour(); long failCount = callbackRepository.countFailByHour(); double failRate = failCount * 100.0 / totalCount; if (failRate > 1) { alertService.sendAlert("回传失败率告警", String.format("失败率: %.2f%%", failRate)); } } } 八、总结 8.1 集成核心要点 指令下发:幂等、可靠、可追溯 库存同步:实时、准确、有兜底 状态回传:及时、完整、可重试 异常处理:自动重试、人工兜底 8.2 最佳实践 实践 说明 消息队列解耦 异步处理,削峰填谷 幂等设计 防止重复处理 重试机制 失败自动重试 监控告警 及时发现问题 系列文章导航 ...

2026-02-02 · maneng

WMS库存盘点实战——保证库存准确率的关键方法

引言:库存准确率的重要性 库存不准的后果: 超卖:系统有货实际没货,客户投诉 滞销:实际有货系统没货,资金占用 财务差异:账实不符,审计风险 库存准确率目标: 电商仓库:> 99.9% 普通仓库:> 99.5% 高价值仓库:> 99.99% 一、盘点类型 1.1 盘点方式对比 类型 说明 频率 适用场景 全盘 盘点所有库存 年度/季度 财务结算、年终 循环盘点 按计划轮流盘点 每日 日常管理 动碰盘点 有变动时盘点 实时 高价值商品 抽盘 随机抽查 每周 抽样检查 盲盘 不显示系统数量 按需 防止作弊 1.2 盘点策略选择 ┌─────────────────┐ │ 库存准确率 │ │ 目标 99.9% │ └────────┬────────┘ │ ┌─────────────────┼─────────────────┐ │ │ │ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 全盘 │ │ 循环盘点 │ │ 动碰盘点 │ │ 年度1次 │ │ 每日执行 │ │ 实时触发 │ └──────────┘ └──────────┘ └──────────┘ │ │ │ ▼ ▼ ▼ 财务结算 日常维护 高价值商品 二、盘点数据模型 2.1 盘点计划 CREATE TABLE t_count_plan ( id BIGINT PRIMARY KEY AUTO_INCREMENT, plan_no VARCHAR(32) NOT NULL COMMENT '计划单号', warehouse_id VARCHAR(32) NOT NULL, plan_name VARCHAR(64) NOT NULL COMMENT '计划名称', count_type VARCHAR(16) NOT NULL COMMENT '盘点类型:FULL/CYCLE/SPOT', -- 盘点范围 scope_type VARCHAR(16) NOT NULL COMMENT '范围类型:ALL/ZONE/SKU/LOCATION', scope_value TEXT COMMENT '范围值(JSON)', -- 计划时间 plan_date DATE NOT NULL COMMENT '计划日期', start_time TIME COMMENT '开始时间', end_time TIME COMMENT '结束时间', status VARCHAR(16) NOT NULL DEFAULT 'CREATED', created_by VARCHAR(32), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_plan_no (plan_no), KEY idx_warehouse_date (warehouse_id, plan_date) ) ENGINE=InnoDB COMMENT='盘点计划'; 2.2 盘点任务 CREATE TABLE t_count_task ( id BIGINT PRIMARY KEY AUTO_INCREMENT, task_no VARCHAR(32) NOT NULL COMMENT '任务单号', plan_no VARCHAR(32) NOT NULL COMMENT '计划单号', warehouse_id VARCHAR(32) NOT NULL, -- 盘点范围 zone_code VARCHAR(16) COMMENT '库区', location_from VARCHAR(32) COMMENT '起始库位', location_to VARCHAR(32) COMMENT '结束库位', -- 执行信息 operator_id VARCHAR(32) COMMENT '盘点员', status VARCHAR(16) NOT NULL DEFAULT 'PENDING', start_time DATETIME, end_time DATETIME, -- 统计 total_locations INT DEFAULT 0 COMMENT '库位数', counted_locations INT DEFAULT 0 COMMENT '已盘库位数', difference_count INT DEFAULT 0 COMMENT '差异数', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_task_no (task_no), KEY idx_plan_no (plan_no) ) ENGINE=InnoDB COMMENT='盘点任务'; 2.3 盘点明细 CREATE TABLE t_count_detail ( id BIGINT PRIMARY KEY AUTO_INCREMENT, task_no VARCHAR(32) NOT NULL, location_code VARCHAR(32) NOT NULL COMMENT '库位', sku_id VARCHAR(32) NOT NULL, -- 数量 system_qty INT NOT NULL COMMENT '系统数量', count_qty INT COMMENT '盘点数量', difference_qty INT COMMENT '差异数量', -- 盘点信息 count_time DATETIME COMMENT '盘点时间', counter_id VARCHAR(32) COMMENT '盘点人', -- 复盘 recount_qty INT COMMENT '复盘数量', recount_time DATETIME, recounter_id VARCHAR(32), status VARCHAR(16) NOT NULL DEFAULT 'PENDING', remark VARCHAR(256), KEY idx_task_no (task_no), KEY idx_location (location_code) ) ENGINE=InnoDB COMMENT='盘点明细'; 三、循环盘点 3.1 循环盘点策略 ABC分类盘点: ...

2026-02-02 · maneng

WMS拣货策略优化——提升仓库出库效率的核心方法

引言:拣货效率决定仓库产能 拣货占仓库作业时间的50%-60%: 拣货效率直接决定发货速度 拣货准确率影响客户满意度 拣货成本是仓储成本的大头 优化拣货的核心目标: 减少行走距离:路径最短 提高拣货准确率:减少错拣 提升人效:单位时间拣更多 一、拣货业务全景 1.1 拣货流程 出库指令 ──> 波次生成 ──> 任务分配 ──> 拣货执行 ──> 复核 ──> 发货 │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ 接收OMS 按规则分波 分配拣货员 PDA扫码 扫码核对 交接物流 1.2 拣货模式对比 模式 说明 效率 准确率 适用场景 单单拣货 一次拣一个订单 低 高 订单量小、高价值 批量拣货 先拣后分 高 中 订单量大、SKU集中 边拣边分 拣货同时分拣 中 高 中等订单量 播种式 先汇总再分播 高 高 大促、爆款 二、波次管理 2.1 什么是波次 波次 = 将多个出库单合并成一个批次处理 ...

2026-02-02 · maneng

WMS入库管理详解——从ASN到上架的全流程设计

引言:入库管理的重要性 入库是仓库的第一道关口: 入库数据准确,后续流程才能顺畅 入库效率高,仓库周转才能快 入库质检严,售后问题才能少 入库管理的核心目标: 准确:收货数量与实际一致 高效:快速完成收货上架 可追溯:每件商品来源清晰 一、入库业务全景 1.1 入库类型 类型 来源 特点 采购入库 供应商送货 有采购单,需质检 退货入库 客户退回 需检验,可能有损坏 调拨入库 其他仓库 有调拨单,已质检 生产入库 自有工厂 有生产单 1.2 入库流程总览 ASN预约 ──> 到货登记 ──> 质检 ──> 收货确认 ──> 上架 │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ 创建预约 扫码核对 质量检验 生成入库单 分配库位 通知仓库 数量清点 合格/不合格 库存增加 PDA扫码 二、ASN预约管理 2.1 什么是ASN ASN(Advance Shipping Notice)= 预到货通知 供应商发货前,提前通知仓库: 什么时候到 送什么货 送多少 ASN的价值: ...

2026-02-02 · maneng

哪些系统适合自研?——跨境电商的特殊性分析

引言:不是所有系统都要自研 上一篇我们讲了自研vs采购的决策框架。但具体到跨境电商,哪些系统适合自研? 跨境电商有其特殊性: 多渠道、多币种、多仓库 复杂的订单逻辑 特殊的仓储需求 跨境合规要求 这些特殊性决定了,有些系统必须自研,有些系统采购更划算。 一、跨境电商的业务特殊性 1.1 多渠道复杂性 渠道类型: 平台渠道:Amazon、eBay、Wish、速卖通 独立站:Shopify、自建站 社交电商:TikTok Shop、Facebook Shop 每个渠道的差异: 渠道 订单结构 API方式 结算周期 特殊规则 Amazon 复杂 REST API 14天 FBA/FBM eBay 中等 REST API 即时 拍卖模式 Shopify 简单 GraphQL 即时 Webhook 速卖通 复杂 REST API 15天 纠纷规则 挑战: 每个渠道的订单格式不同 每个渠道的API不同 每个渠道的规则不同 需要统一管理 1.2 多币种复杂性 涉及的币种: 销售币种:USD、EUR、GBP、JPY、AUD… 采购币种:CNY、USD 结算币种:USD、CNY 挑战: 汇率波动影响利润 多币种成本核算 汇兑损益处理 1.3 多仓库复杂性 仓库类型: 国内仓:深圳、义乌 海外仓:美国、欧洲、日本 FBA仓:亚马逊仓库 第三方仓:海外第三方仓 挑战: 库存分布在多个仓库 不同仓库的操作流程不同 跨仓调拨 库存同步 1.4 订单逻辑复杂性 复杂场景: ...

2026-01-29 · maneng

WMS仓储系统自研实战——架构设计与核心流程

引言:WMS的重要性 WMS(Warehouse Management System)是仓储执行的大脑: 管理仓库内所有实物操作 直接影响发货效率和库存准确率 是OMS订单履约的执行者 一个好的WMS系统,可以让仓库效率提升50%以上,库存准确率达到99.9%。 一、WMS系统定位 1.1 WMS在系统矩阵中的位置 OMS │ │ 出库指令 ▼ ┌─────────────────────────────────────────────────────┐ │ WMS │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │入库管理 │ │库位管理 │ │出库管理 │ │库存管理 │ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ └───────────────────────┬─────────────────────────────┘ │ │ 发货交接 ▼ TMS 1.2 WMS的核心职责 职责 说明 入库管理 收货、质检、上架 库位管理 库位分配、库存查询 出库管理 波次、拣货、复核、发货 库存管理 盘点、调拨、冻结 设备对接 PDA、打印机、电子秤 1.3 WMS与OMS的边界 功能 OMS WMS 可售库存 ✓ 实物库存 ✓ 库位库存 ✓ 订单拆分 ✓ 波次生成 ✓ 拣货执行 ✓ 二、架构设计 2.1 整体架构 ┌─────────────────────────────────────────────────────┐ │ 接入层 │ │ OMS接口 │ ERP接口 │ PDA接口 │ 打印接口 │ └─────────────────────┬───────────────────────────────┘ │ ┌─────────────────────▼───────────────────────────────┐ │ 服务层 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 入库服务 │ │ 出库服务 │ │ 库存服务 │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 库位服务 │ │ 波次服务 │ │ 策略引擎 │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └─────────────────────┬───────────────────────────────┘ │ ┌─────────────────────▼───────────────────────────────┐ │ 数据层 │ │ MySQL │ Redis │ RocketMQ │ └─────────────────────────────────────────────────────┘ 2.2 核心服务说明 入库服务: ...

2026-01-29 · maneng

WMS未来趋势:智能化与自动化

引言 WMS正在从传统的信息系统向智能化、自动化方向演进。本文探讨WMS的未来发展趋势,包括AI、机器人、物联网和云原生技术。 1. 智能仓储的发展趋势 1.1 三个发展阶段 第一阶段:人工仓储(1980s-2000s) 特点: - 纸质单据管理 - 人工拣货、人工盘点 - 库存准确率: <90% - 效率:50单/小时/人 第二阶段:半自动化仓储(2000s-2020s) 特点: - WMS数字化管理 - RF扫描、条码管理 - 波次拣货、路径优化 - 库存准确率: 95-99% - 效率:100-150单/小时/人 第三阶段:智能化仓储(2020s-未来) 特点: - AI决策、机器人作业 - 无人拣货、自动分拣 - 数字孪生、预测性补货 - 库存准确率: >99.9% - 效率:300+单/小时/机器人 2. AI在WMS中的应用 2.1 智能拣货路径规划 传统方式:固定算法(S型、Z型、TSP) AI方式:强化学习优化 import gym import numpy as np from stable_baselines3 import PPO # 定义拣货环境 class PickingEnv(gym.Env): def __init__(self, warehouse_layout, pick_tasks): self.layout = warehouse_layout self.tasks = pick_tasks self.current_location = (0, 0) # 起点 def step(self, action): # action: 下一个要去的库位 next_location = self.tasks[action] distance = self.calculate_distance(self.current_location, next_location) reward = -distance # 负的距离作为奖励 self.current_location = next_location return state, reward, done, info # 训练AI模型 model = PPO("MlpPolicy", env, verbose=1) model.learn(total_timesteps=100000) # 使用AI规划路径 obs = env.reset() for _ in range(20): action, _ = model.predict(obs) obs, reward, done, _ = env.step(action) 效果: ...

2025-11-22 · maneng

WMS-TMS集成:从出库到配送的高效协同

引言 WMS与TMS的集成是仓储与运输协同的关键,直接影响配送效率和客户体验。本文将探讨WMS-TMS集成的技术方案。 1. 集成场景 1.1 发货场景 WMS出库完成 → 推送发货信息到TMS → TMS创建运单 → 承运商揽货 1.2 签收场景 TMS配送完成 → 推送签收信息到WMS → WMS更新出库单状态 2. 接口设计 2.1 发货信息推送 请求体: { "orderNo": "OMS202511220001", "waybillNo": "SF1234567890", "shipperAddress": "北京市大兴区XX仓库", "consigneeAddress": "北京市朝阳区XX街道XX号", "consignee": { "name": "张三", "phone": "13800138000" }, "cargoInfo": { "weight": 5.0, "volume": 0.02, "quantity": 2, "value": 198.00 }, "timeRequirement": "STANDARD" } 2.2 配送状态回调 { "waybillNo": "SF1234567890", "status": "DELIVERED", "deliveredTime": "2025-11-23T15:00:00", "signer": "张三", "signImage": "https://xxx.com/sign.jpg" } 3. 运费结算 3.1 运费记录 @Service public class FreightRecordService { public void recordFreight(String waybillNo, BigDecimal freight) { FreightRecord record = new FreightRecord(); record.setWaybillNo(waybillNo); record.setFreight(freight); record.setStatus("PENDING"); freightRecordMapper.insert(record); } } 3.2 定期对账 @Component public class FreightReconciliationTask { @Scheduled(cron = "0 0 2 1 * ?") // 每月1日凌晨2点 public void reconcile() { LocalDate lastMonth = LocalDate.now().minusMonths(1); List<FreightRecord> records = freightRecordMapper .selectByMonth(lastMonth); // 生成对账单 FreightBill bill = new FreightBill(); bill.setBillNo("BILL" + lastMonth.format(DateTimeFormatter.ofPattern("yyyyMM"))); bill.setRecords(records); bill.setTotalFreight(records.stream() .map(FreightRecord::getFreight) .reduce(BigDecimal.ZERO, BigDecimal::add) ); freightBillService.create(bill); } } 4. 异常处理 4.1 拒收处理 public void handleReject(String waybillNo, String reason) { // 1. 更新运单状态 Waybill waybill = waybillMapper.selectByNo(waybillNo); waybill.setStatus("REJECTED"); waybill.setRejectReason(reason); waybillMapper.updateById(waybill); // 2. 通知WMS创建退货入库单 wmsService.createReturnInbound(waybillNo); // 3. 通知OMS更新订单状态 omsService.updateOrderStatus(waybill.getOrderNo(), "REJECTED"); } 5. 实战案例:顺丰的WMS-TMS集成 技术方案: ...

2025-11-22 · maneng

WMS生产实践与故障排查

引言 本文分享WMS生产环境的实战经验,包括部署架构、常见故障排查、性能调优和大促保障。 1. 生产环境部署 1.1 服务器规划 小型WMS(日订单<5000单): 应用服务器: 2台(4核8G) 数据库服务器: 1台(8核16G)+ 从库1台(备份) Redis服务器: 1台(4核8G) 中型WMS(日订单5000-50000单): 应用服务器: 4台(8核16G)+ 负载均衡 数据库服务器: 1主2从(16核32G)+ 读写分离 Redis集群: 3台(8核16G) 消息队列: 3台(RabbitMQ集群) 大型WMS(日订单>50000单): 应用服务器: 10+台(16核32G)+ Kubernetes 数据库服务器: MySQL主从 + 分库分表 Redis集群: 6台(哨兵模式) 消息队列: Kafka集群(5台) 监控服务: Prometheus + Grafana 1.2 高可用架构 ┌─────────────────────────────────────┐ │ Nginx负载均衡(主备) │ └─────────────────────────────────────┘ ↓ ↓ ↓ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ WMS-1 │ │ WMS-2 │ │ WMS-3 │ └─────────┘ └─────────┘ └─────────┘ ↓ ↓ ↓ ┌─────────────────────────────────┐ │ MySQL主从(读写分离) │ │ Master + Slave1 + Slave2 │ └─────────────────────────────────┘ ↓ ┌─────────────────────────────────┐ │ Redis哨兵模式 │ │ Master + Slave + Sentinel │ └─────────────────────────────────┘ 1.3 容灾备份策略 数据库备份: ...

2025-11-22 · maneng

OMS-WMS集成:从订单到出库的无缝衔接

引言 OMS与WMS的集成是供应链系统的核心环节,直接影响订单履约效率。本文将深入探讨OMS-WMS集成的方案设计和技术实现。 1. 集成场景 1.1 出库场景 流程: 1. OMS推送出库指令 ↓ 2. WMS创建出库单 ↓ 3. WMS拣货打包 ↓ 4. WMS出库确认 ↓ 5. WMS回调OMS(运单号、发货时间) 1.2 入库场景 采购入库: 采购系统 → OMS → WMS创建入库单 退货入库: OMS创建退货单 → WMS验收入库 2. 接口设计 2.1 出库指令接口 接口定义: POST /api/wms/outbound/create Content-Type: application/json 请求体: { "orderNo": "OMS202511220001", "warehouseCode": "WH001", "priority": "HIGH/NORMAL/LOW", "timeRequirement": "STANDARD/EXPRESS", "items": [ { "sku": "SKU001", "quantity": 2, "batchNo": "BATCH001" } ], "consignee": { "name": "张三", "phone": "13800138000", "province": "北京市", "city": "北京市", "district": "朝阳区", "address": "XX街道XX号" } } 响应体: { "code": 200, "message": "success", "data": { "outboundNo": "WMS202511220001", "status": "PENDING" } } 2.2 出库确认回调 接口定义: ...

2025-11-22 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...