自动化立体仓库 - WMS系统
zwl
昨天 2a2f094b447c604ca2884922586df32f0665b81c
双伸出库改成订单出库
完成转订单
3个文件已修改
100 ■■■■ 已修改文件
src/main/java/com/zy/asrs/service/impl/OrderDetlPakoutServiceImpl.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/OrderDetlPakoutServiceImpl.java
@@ -28,12 +28,16 @@
    @Override
    public OrderDetlPakout selectItem(Long orderId, String matnr, String batch, String brand, String standby1, String standby2, String standby3, String boxType1, String boxType2, String boxType3) {
        return this.baseMapper.selectItem(orderId, matnr, batch,brand,standby1,standby2,standby3,boxType1,boxType2,boxType3);
        // 延迟出库后,man_order_detl_pakout 会按托盘拆明细。
        // 旧的 orderId + 物料维度可能命中多条记录,不能再用 mapper 返回单对象的 selectOne 语义。
        // 这里统一改为列表查询并按 id 取第一条,避免 TooManyResultsException;需要精确回写时请优先使用 pallet_id。
        return selectFirst(buildItemWrapper(orderId, null, matnr, batch, brand, standby1, standby2, standby3, boxType1, boxType2, boxType3));
    }
    @Override
    public OrderDetlPakout selectItem(String orderNo, String matnr, String batch, String brand, String standby1, String standby2, String standby3, String boxType1, String boxType2, String boxType3) {
        return this.baseMapper.selectItemByOrderNo(orderNo, matnr, batch,brand,standby1,standby2,standby3,boxType1,boxType2,boxType3);
        // 同上,orderNo + 物料维度在新模型中不保证唯一,只作为旧数据的兜底匹配。
        return selectFirst(buildItemWrapper(null, orderNo, matnr, batch, brand, standby1, standby2, standby3, boxType1, boxType2, boxType3));
    }
    @Override
@@ -41,9 +45,13 @@
        if (Cools.isEmpty(orderNo) || Cools.isEmpty(palletId)) {
            return null;
        }
        return this.selectOne(new EntityWrapper<OrderDetlPakout>()
                .eq("order_no", orderNo)
                .eq("pallet_id", palletId));
        // orderNo + palletId 是延迟出库订单明细的精确匹配键。
        // 仍然使用 selectList 取第一条,防止历史脏数据里同一托盘重复时 selectOne 直接中断定时线程。
        EntityWrapper<OrderDetlPakout> wrapper = new EntityWrapper<>();
        wrapper.eq("order_no", orderNo)
                .eq("pallet_id", palletId)
                .orderBy("id", true);
        return selectFirst(wrapper);
    }
    @Override
@@ -115,4 +123,32 @@
    public boolean increaseWorkQty(Long orderId, String matnr, String batch, String brand, String standby1, String standby2, String standby3, String boxType1, String boxType2, String boxType3, Double workQty) {
        return this.baseMapper.increaseWorkQty(orderId, matnr, batch,brand,standby1,standby2,standby3,boxType1,boxType2,boxType3, workQty) > 0;
    }
    private EntityWrapper<OrderDetlPakout> buildItemWrapper(Long orderId, String orderNo, String matnr, String batch, String brand,
                                                           String standby1, String standby2, String standby3,
                                                           String boxType1, String boxType2, String boxType3) {
        EntityWrapper<OrderDetlPakout> wrapper = new EntityWrapper<>();
        wrapper.eq("matnr", matnr)
                .eq("batch", batch)
                .eq("brand", brand)
                .eq("standby1", standby1)
                .eq("standby2", standby2)
                .eq("standby3", standby3)
                .eq("box_type1", boxType1)
                .eq("box_type2", boxType2)
                .eq("box_type3", boxType3)
                .orderBy("id", true);
        if (!Cools.isEmpty(orderId)) {
            wrapper.eq("order_id", orderId);
        }
        if (!Cools.isEmpty(orderNo)) {
            wrapper.eq("order_no", orderNo);
        }
        return wrapper;
    }
    private OrderDetlPakout selectFirst(EntityWrapper<OrderDetlPakout> wrapper) {
        List<OrderDetlPakout> rows = this.selectList(wrapper);
        return Cools.isEmpty(rows) ? null : rows.get(0);
    }
}
src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java
@@ -539,14 +539,8 @@
                    }
                    for (WrkDetl wrkDetl : wrkDetls101) {
                        // 更新订单完成数量
                        OrderDetlPakout orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        if (orderDetlPakout == null) {
                            orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                    wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        }
                        try {
                            if (!increasePakoutOrderQty(wrkMast, wrkDetl, orderDetlPakout)) {
                            if (!increasePakoutOrderQty(wrkMast, wrkDetl)) {
                                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                return FAIL.setMsg("全板出库 ===>> 更新订单完成数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getSourceLocNo() + "]");
                            }
@@ -592,10 +586,8 @@
                            }
                        }
                        // 更新订单完成数量
                        OrderDetlPakout orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        try {
                            if (!increasePakoutOrderQty(wrkMast, wrkDetl, orderDetlPakout)) {
                            if (!increasePakoutOrderQty(wrkMast, wrkDetl)) {
                                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                return FAIL.setMsg("并板途中捡料 ===>> 更新订单完成数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getSourceLocNo() + "]");
                            }
@@ -658,22 +650,36 @@
     * 新增的延迟出库订单明细按 pallet_id 保存接口托盘号,因此优先使用 orderNo + palletId 精确回写;
     * 如果是历史订单或旧数据没有 pallet_id,则退回原来的物料/批次/备用字段匹配方式。
     */
    private boolean increasePakoutOrderQty(WrkMast wrkMast, WrkDetl wrkDetl, OrderDetlPakout matchedOrderDetl) {
    private boolean increasePakoutOrderQty(WrkMast wrkMast, WrkDetl wrkDetl) {
        if (wrkDetl == null || Cools.isEmpty(wrkDetl.getOrderNo())) {
            return true;
        }
        String palletId = null;
        if (wrkDetl != null && !Cools.isEmpty(wrkDetl.getZpallet())) {
        if (!Cools.isEmpty(wrkDetl.getZpallet())) {
            palletId = wrkDetl.getZpallet();
        } else if (wrkMast != null) {
            palletId = wrkMast.getBarcode();
        }
        // stationId > 600 的延迟出库订单是一托盘一行明细;同一订单、物料、批次、进仓编号下会有多行。
        // 因此完成回写必须优先用 orderNo + palletId 精确定位,否则旧的物料维度查询会命中多行。
        if (!Cools.isEmpty(palletId)
                && orderDetlPakoutService.increaseQtyByOrderNoAndPallet(wrkDetl.getOrderNo(), palletId, wrkDetl.getAnfme())) {
            return true;
        }
        // 兼容历史订单:旧数据可能没有 pallet_id,只能退回原来的物料/批次/备用字段匹配。
        // 这里不再调用批量 update SQL,而是先取一条明细后按 id 更新,避免重复明细时把多行 qty 一起加上。
        OrderDetlPakout matchedOrderDetl = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
        if (Cools.isEmpty(matchedOrderDetl)) {
            return true;
        }
        return orderDetlPakoutService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                matchedOrderDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3(), wrkDetl.getAnfme());
        matchedOrderDetl.setQty(safeDouble(matchedOrderDetl.getQty()) + safeDouble(wrkDetl.getAnfme()));
        matchedOrderDetl.setUpdateTime(new Date());
        return orderDetlPakoutService.updateById(matchedOrderDetl);
    }
    private double safeDouble(Double value) {
        return value == null ? 0.0D : value;
    }
}
src/main/resources/application.yml
@@ -152,21 +152,21 @@
  keepAliveSeconds: 60
  connectionTimeoutSeconds: 10
  persistenceDir: .local/iot-mqtt
  caCertPath: D:/work/work-zy/gsl/zy-wms-gsl/src/main/resources/iot-certs/AmazonRootCA1.pem
  clientCertPath: D:/work/work-zy/gsl/zy-wms-gsl/src/main/resources/iot-certs/device-certificate.pem.crt
  privateKeyPath: D:/work/work-zy/gsl/zy-wms-gsl/src/main/resources/iot-certs/device-private.pem.key
  caCertPath: D:\working\Project Documentation\临港哥斯拉项目\iot/AmazonRootCA1.pem
  clientCertPath: D:\working\Project Documentation\临港哥斯拉项目\iot/device-certificate.pem.crt
  privateKeyPath: D:\working\Project Documentation\临港哥斯拉项目\iot/device-private.pem.key
  topics:
    #亚马逊发送组托给wms,在托盘上收到纸箱后,发布堆垛指令以将托盘发送到仓库。
    egressStow: glenn/instruction/icng/egress/asrs/stow
    egressStow: glenn/instruction/test_icng/egress/asrs/stow
    #亚马逊发送出库指令给wms,启动拣选请求后,发布拣选指令以引导ASRS从料箱中取货。
    egressPick: glenn/instruction/icng/egress/asrs/pick
    egressPick: glenn/instruction/test_icng/egress/asrs/pick
    #wms入库完成发送给亚马逊,ASRS实际拖拽托盘到料箱后,发布堆垛动作以同步BPS数据。
    egressFeedback: glenn/instruction/icng/egress/asrs/feedback
    egressFeedback: glenn/instruction/test_icng/egress/asrs/feedback
    #wms出库完成发送给亚马逊,在ASRS实际从料箱取货后,发布拣选动作sz XBPS数据。
    ingressStow: glenn/instruction/icng/ingress/asrs/stow
    ingressStow: glenn/instruction/test_icng/ingress/asrs/stow
    #ASRS 接收到 XBPS 指令后,向反馈XBPS 发送响应。
    ingressPick: glenn/instruction/icng/ingress/asrs/pick
    ingressPick: glenn/instruction/test_icng/ingress/asrs/pick
    #在XBPs收到ASRS操作后,向反馈ASRS发送响应
    ingressFeedback: glenn/instruction/icng/ingress/asrs/feedback
    ingressFeedback: glenn/instruction/test_icng/ingress/asrs/feedback
  pickStationMappings:
    ASRSOutbound1: 101