diff --git a/src/main/java/com/gaotao/modules/api/service/impl/WmsMessageServiceImpl.java b/src/main/java/com/gaotao/modules/api/service/impl/WmsMessageServiceImpl.java index 1901519d..c38e9535 100644 --- a/src/main/java/com/gaotao/modules/api/service/impl/WmsMessageServiceImpl.java +++ b/src/main/java/com/gaotao/modules/api/service/impl/WmsMessageServiceImpl.java @@ -804,11 +804,10 @@ public class WmsMessageServiceImpl implements WmsMessageService { } /** - * @Description 执行自动化托运托盘移库(IFS调用改为写入队列表)- rqrq - * @param request 移库请求参数 - * @return 处理结果 * @author rqrq - * @date 2026/08/24 + * @Description 执行自动化托运托盘移库(IFS调用改为写入队列表)。开头只收在库Y且标签表存在的明细,查不到或非Y的留盘不抛错,避免脏标签把WCS/AGV整托打死 - rqrq + * @param request 移库请求,site/palletId/目标仓库库位来自回调,username用于事务审计 - rqrq + * @return 处理结果说明;无可搬标签时返回无需移库,调用方仍可更新托盘位置 - rqrq */ @Override @Transactional(rollbackFor = Exception.class) @@ -834,43 +833,16 @@ public class WmsMessageServiceImpl implements WmsMessageService { pallet.setLocationCode(request.getToStation()); pallet.setWcsLocation(request.getToStation()); - - String fromWarehouseId; - String fromLocationId; - - // 从pallet_detail的第一条记录获取serialNo,查询handling_unit的仓库和库位 - rqrq - PalletDetail firstPalletDetail = palletDetails.get(0); - HandlingUnit firstHu = handlingUnitService.lambdaQuery() - .eq(HandlingUnit::getSite, request.getSite()) - .eq(HandlingUnit::getUnitId, firstPalletDetail.getSerialNo()) - .one(); - - if (firstHu == null) { - throw new RuntimeException("未找到条码对应的处理单元:" + firstPalletDetail.getSerialNo()); - } - - fromWarehouseId = firstHu.getWarehouseId(); - fromLocationId = firstHu.getLocationId(); - - if(fromWarehouseId.equals(request.getToWarehouseId())&&fromLocationId.equals(request.getToLocationId())){ - return "托盘无需执行移库操作:" + request.getPalletId(); - } - - // 5. 获取条码对应的HandlingUnit信息 - List serialNos = palletDetails.stream() - .map(PalletDetail::getSerialNo) - .collect(Collectors.toList()); - - List handlingUnits = handlingUnitService.lambdaQuery() - .eq(HandlingUnit::getSite, request.getSite()) - .in(HandlingUnit::getUnitId, serialNos) - .list(); - + + // 只收可自动搬库的Y标签:查不到/非Y/数量无效/已在目标库的明细留盘,不按第一条标签决定整托 - rqrq + List handlingUnits = collectAutoTransferHandlingUnits( + request.getSite(), request.getPalletId(), request.getToWarehouseId(), request.getToLocationId(), palletDetails); if (handlingUnits.isEmpty()) { - throw new RuntimeException("未找到托盘上的条码信息"); + return "托盘无需执行移库操作:" + request.getPalletId(); } - - + + // 事务头来源仓库取第一份可搬Y标签;后续明细仍按标签自身库位分组,兼容混库位 - rqrq + String fromWarehouseId = handlingUnits.get(0).getWarehouseId(); // 6. 生成移库出库和入库的事务号 TransNoControl stoTransData = transNoControlService.getTransNo(request.getSite(), "STO", 10); @@ -1104,6 +1076,89 @@ public class WmsMessageServiceImpl implements WmsMessageService { detailSub.setEngChgLevel(hu.getEngChgLevel()); // 添加工程更改级别 - rqrq return detailSub; } + + /** + * @author rqrq + * @Description 自动移库开头收紧可搬标签:只保留handling_unit存在、in_stock_flag=Y、数量>0、且仓库或库位与目标不同的标签。 + * 查不到、非Y、数量无效或已在目标库的明细留在托盘不抛错、不删pallet_detail,避免脏数据把整托回调打死。 + * 同一条码只收一次,防止重复明细把数量算两次。- rqrq + * @param site 请求工厂,必须与托盘和标签site一致,禁止登录态兜底 - rqrq + * @param palletId 托盘号,仅用于日志定位留盘标签 - rqrq + * @param toWarehouseId 目标仓库,与当前仓库都相同且库位也相同时该标签跳过 - rqrq + * @param toLocationId 目标库位,与当前库位都相同且仓库也相同时该标签跳过 - rqrq + * @param palletDetails 当前托盘全部明细,本方法不改明细表 - rqrq + * @return 需要自动移库的Y标签列表,空表示整托跳过移库 - rqrq + */ + private List collectAutoTransferHandlingUnits(String site, String palletId, String toWarehouseId, + String toLocationId, List palletDetails) { + List movableUnits = new ArrayList(); + if (palletDetails == null || palletDetails.isEmpty()) { + return movableUnits; + } + List serialNos = new ArrayList(); + for (PalletDetail detail : palletDetails) { + if (detail == null || !StringUtils.hasText(detail.getSerialNo())) { + continue; + } + serialNos.add(detail.getSerialNo().trim()); + } + if (serialNos.isEmpty()) { + log.warn("自动移库跳过:托盘明细没有有效条码,site={},palletId={} - rqrq", site, palletId); + return movableUnits; + } + // 按site+条码批量查标签主数据;查不到的后面按明细逐条留盘,这里空结果不抛错 - rqrq + List foundUnits = handlingUnitService.lambdaQuery() + .eq(HandlingUnit::getSite, site) + .in(HandlingUnit::getUnitId, serialNos) + .list(); + Map huByUnitId = new LinkedHashMap(); + if (foundUnits != null) { + for (HandlingUnit hu : foundUnits) { + if (hu != null && StringUtils.hasText(hu.getUnitId())) { + huByUnitId.put(hu.getUnitId().trim(), hu); + } + } + } + Set acceptedSerialNos = new HashSet(); + String targetWarehouse = StringUtils.hasText(toWarehouseId) ? toWarehouseId.trim() : ""; + String targetLocation = StringUtils.hasText(toLocationId) ? toLocationId.trim() : ""; + for (PalletDetail detail : palletDetails) { + if (detail == null || !StringUtils.hasText(detail.getSerialNo())) { + continue; + } + String serialNo = detail.getSerialNo().trim(); + if (!acceptedSerialNos.add(serialNo)) { + continue; + } + HandlingUnit hu = huByUnitId.get(serialNo); + if (hu == null) { + log.warn("自动移库留盘:标签表不存在,site={},palletId={},serialNo={} - rqrq", site, palletId, serialNo); + continue; + } + if (!"Y".equalsIgnoreCase(StringUtils.hasText(hu.getInStockFlag()) ? hu.getInStockFlag().trim() : "")) { + log.warn("自动移库留盘:标签非在库Y,site={},palletId={},serialNo={},inStockFlag={} - rqrq", + site, palletId, serialNo, hu.getInStockFlag()); + continue; + } + if (hu.getQty() == null || hu.getQty().compareTo(BigDecimal.ZERO) <= 0) { + log.warn("自动移库留盘:标签数量无效,site={},palletId={},serialNo={},qty={} - rqrq", + site, palletId, serialNo, hu.getQty()); + continue; + } + String currentWarehouse = StringUtils.hasText(hu.getWarehouseId()) ? hu.getWarehouseId().trim() : ""; + String currentLocation = StringUtils.hasText(hu.getLocationId()) ? hu.getLocationId().trim() : ""; + if (targetWarehouse.equals(currentWarehouse) && targetLocation.equals(currentLocation)) { + log.info("自动移库跳过:标签已在目标仓库库位,site={},palletId={},serialNo={} - rqrq", + site, palletId, serialNo); + continue; + } + movableUnits.add(hu); + } + if (movableUnits.isEmpty()) { + log.info("自动移库跳过:托盘没有可搬的在库Y标签,site={},palletId={} - rqrq", site, palletId); + } + return movableUnits; + } /** * 获取托盘明细信息