diff --git a/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java b/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java index 168994ba..29412a65 100644 --- a/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java +++ b/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java @@ -434,22 +434,17 @@ public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService } int splitType = Optional.ofNullable(bo.getSplitType()).orElse(0); - List Ids = Optional.ofNullable(bo.getSplitIds()).orElse(new ArrayList<>()); - - - // 合并所有待拆分的ID - Set splitIds = new HashSet<>(); - splitIds.addAll(Ids); + List splitIds = Optional.ofNullable(bo.getSplitIds()).orElse(new ArrayList<>()); if (splitIds.isEmpty()) { throw new ServiceException("待拆分库位ID列表不能为空"); } - // 根据列标识查询该列的所有库位(第一层和第二层) + // 根据列标识查询该列的所有三级库位 List columnLocations = baseMapper.selectList(Wrappers.lambdaQuery() .like(WmsActualWarehouse::getActualWarehouseCode, columnFlag) .eq(WmsActualWarehouse::getDelFlag, 0) - .eq(WmsActualWarehouse::getActualWarehouseType, 3) // 只查询三级库位 + .eq(WmsActualWarehouse::getActualWarehouseType, 3) .orderByAsc(WmsActualWarehouse::getActualWarehouseCode)); if (CollUtil.isEmpty(columnLocations)) { @@ -468,107 +463,121 @@ public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService } } - // 第一步:先创建所有子库位(不设置编码) + // 存储需要插入/更新的子库位 List toInsert = new ArrayList<>(); + List toUpdate = new ArrayList<>(); // 1. 处理需要拆分的库位(每个拆分为2个子库位) for (WmsActualWarehouse location : splitLocations) { - // 生成第一个子库位 - WmsActualWarehouse subLocation1 = new WmsActualWarehouse(); - subLocation1.setParentId(location.getActualWarehouseId()); - subLocation1.setActualWarehouseType(4L); // 四级节点 - subLocation1.setSortNo(Optional.ofNullable(location.getSortNo()).orElse(0L)); - subLocation1.setIsEnabled(1); - subLocation1.setSplitStatus(1); - subLocation1.setSplitType(splitType); - toInsert.add(subLocation1); + // 先查询该父库位下是否存在已逻辑删除的子库位(合并后保留的) + List existingChildren = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(WmsActualWarehouse::getParentId, location.getActualWarehouseId()) + .eq(WmsActualWarehouse::getActualWarehouseType, 4) + .eq(WmsActualWarehouse::getDelFlag, 1)); // 查询已逻辑删除的子库位 - // 生成第二个子库位 - WmsActualWarehouse subLocation2 = new WmsActualWarehouse(); - subLocation2.setParentId(location.getActualWarehouseId()); - subLocation2.setActualWarehouseType(4L); // 四级节点 - subLocation2.setSortNo(Optional.ofNullable(location.getSortNo()).orElse(0L)); - subLocation2.setIsEnabled(1); - subLocation2.setSplitStatus(1); - subLocation2.setSplitType(splitType); - toInsert.add(subLocation2); + if (CollUtil.isNotEmpty(existingChildren) && existingChildren.size() == 2) { + // 复用原有子库位:恢复启用状态,更新拆分类型 + for (WmsActualWarehouse child : existingChildren) { + child.setDelFlag(0); // 恢复未删除 + child.setIsEnabled(1); + child.setSplitStatus(1); + child.setSplitType(splitType); + toUpdate.add(child); + } + } else { + // 无原有子库位,新建2个子库位(暂不设置编码) + WmsActualWarehouse sub1 = createSubLocation(location, splitType); + WmsActualWarehouse sub2 = createSubLocation(location, splitType); + toInsert.add(sub1); + toInsert.add(sub2); + } } - // 2. 处理剩余库位(每个拆分为1个子库位,保持原层级) + // 2. 处理剩余库位(每个拆分为1个子库位) for (WmsActualWarehouse remainingLocation : remainingLocations) { - String baseCode = remainingLocation.getActualWarehouseCode(); + // 先查询是否存在已逻辑删除的子库位 + List existingChildren = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(WmsActualWarehouse::getParentId, remainingLocation.getActualWarehouseId()) + .eq(WmsActualWarehouse::getActualWarehouseType, 4) + .eq(WmsActualWarehouse::getDelFlag, 1)); - // 生成剩余库位的子库位 - WmsActualWarehouse remainingSubLocation = new WmsActualWarehouse(); - remainingSubLocation.setParentId(remainingLocation.getActualWarehouseId()); - remainingSubLocation.setActualWarehouseType(4L); // 四级节点 - remainingSubLocation.setSortNo(Optional.ofNullable(remainingLocation.getSortNo()).orElse(0L)); - remainingSubLocation.setIsEnabled(1); - remainingSubLocation.setSplitStatus(1); - remainingSubLocation.setSplitType(splitType); - toInsert.add(remainingSubLocation); + if (CollUtil.isNotEmpty(existingChildren)) { + // 复用原有子库位 + WmsActualWarehouse child = existingChildren.get(0); + child.setDelFlag(0); + child.setIsEnabled(1); + child.setSplitStatus(1); + child.setSplitType(splitType); + toUpdate.add(child); + } else { + // 新建子库位 + WmsActualWarehouse sub = createSubLocation(remainingLocation, splitType); + toInsert.add(sub); + } } // 3. 验证总数 - int expectedSplitSubLocations = splitLocations.size() * 2; - int expectedRemainingSubLocations = remainingLocations.size() * 1; - int expectedTotalSubLocations = expectedSplitSubLocations + expectedRemainingSubLocations; - int actualTotalSubLocations = toInsert.size(); + int expectedSplitSub = splitLocations.size() * 2; + int expectedRemainingSub = remainingLocations.size() * 1; + int expectedTotal = expectedSplitSub + expectedRemainingSub; + // 实际总数 = 新增数 + 复用数 + int actualTotal = toInsert.size() + toUpdate.size(); - if (actualTotalSubLocations != expectedTotalSubLocations) { + if (actualTotal != expectedTotal) { throw new ServiceException(String.format( - "子库位生成数量不匹配,期望%d个(拆分库位:%d个→%d个,剩余库位:%d个→%d个),实际生成%d个", - expectedTotalSubLocations, - splitLocations.size(), expectedSplitSubLocations, - remainingLocations.size(), expectedRemainingSubLocations, - actualTotalSubLocations - )); + "子库位数量不匹配,期望%d个,实际新增%d个+复用%d个=%d个", + expectedTotal, toInsert.size(), toUpdate.size(), actualTotal)); } - // 4. 批量插入子库位(先插入获取ID) + // 4. 批量插入新子库位 if (!toInsert.isEmpty()) { - boolean ok = baseMapper.insertBatch(toInsert); - if (!ok) { + boolean insertOk = baseMapper.insertBatch(toInsert); + if (!insertOk) { throw new ServiceException("新增子库位失败"); } } - // 第二步:重新生成编码 - String prefix = columnFlag; - List toUpdate = new ArrayList<>(); - - // 1. 先把所有子库位按父库位排序 - List sortedSubLocations = new ArrayList<>(toInsert); - sortedSubLocations.sort((a, b) -> { - // 按父库位在原列中的顺序排序 - Long parentA = a.getParentId(); - Long parentB = b.getParentId(); - int indexA = columnLocations.stream().map(WmsActualWarehouse::getActualWarehouseId).collect(Collectors.toList()).indexOf(parentA); - int indexB = columnLocations.stream().map(WmsActualWarehouse::getActualWarehouseId).collect(Collectors.toList()).indexOf(parentB); - return Integer.compare(indexA, indexB); - }); - - // 2. 遍历排序后的子库位,每2个为一组生成编码(序号递增,后缀固定1、2) - for (int i = 0; i < sortedSubLocations.size(); i++) { - WmsActualWarehouse sub = sortedSubLocations.get(i); - int sequenceNum = (i / 2) + 1; // 每2个子库位对应一个序号(0→1,1→1,2→2,3→2...) - int layer = (i % 2) + 1; // 每组内固定1、2后缀(0→1,1→2,2→1,3→2...) - - // 生成编码:前缀-两位序号-层级(如F2B1-X01-1、F2B1-X01-2、F2B1-X02-1...) - String newCode = String.format("%s-X%02d-%d", prefix, sequenceNum, layer); - sub.setActualWarehouseCode(newCode); - sub.setActualWarehouseName(newCode); - toUpdate.add(sub); - } - - // 3. 批量更新编码 + // 5. 批量更新复用的子库位(恢复状态) if (!toUpdate.isEmpty()) { - for (WmsActualWarehouse item : toUpdate) { - baseMapper.updateById(item); + for (WmsActualWarehouse child : toUpdate) { + baseMapper.updateById(child); } } - // 6. 更新该列所有被拆分库位的状态 + // 6. 统一生成/更新子库位编码(包含新增和复用的) + List allSubLocations = new ArrayList<>(); + allSubLocations.addAll(toInsert); + allSubLocations.addAll(toUpdate); + + // 按父库位排序(保持物理顺序) + allSubLocations.sort((a, b) -> { + Long parentA = a.getParentId(); + Long parentB = b.getParentId(); + int idxA = columnLocations.stream().map(WmsActualWarehouse::getActualWarehouseId).collect(Collectors.toList()).indexOf(parentA); + int idxB = columnLocations.stream().map(WmsActualWarehouse::getActualWarehouseId).collect(Collectors.toList()).indexOf(parentB); + return Integer.compare(idxA, idxB); + }); + + // 生成规范编码 + String prefix = columnFlag; + List codeToUpdate = new ArrayList<>(); + for (int i = 0; i < allSubLocations.size(); i++) { + WmsActualWarehouse sub = allSubLocations.get(i); + int sequenceNum = (i / 2) + 1; + int layer = (i % 2) + 1; + String newCode = String.format("%s-X%02d-%d", prefix, sequenceNum, layer); + + sub.setActualWarehouseCode(newCode); + sub.setActualWarehouseName(newCode); + codeToUpdate.add(sub); + } + + // 批量更新编码 + for (WmsActualWarehouse sub : codeToUpdate) { + baseMapper.updateById(sub); + } + + // 7. 更新父库位拆分状态 for (WmsActualWarehouse location : columnLocations) { WmsActualWarehouse upd = new WmsActualWarehouse(); upd.setActualWarehouseId(location.getActualWarehouseId()); @@ -578,53 +587,83 @@ public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService } } + /** + * 创建子库位基础对象(通用方法) + */ + private WmsActualWarehouse createSubLocation(WmsActualWarehouse parent, int splitType) { + WmsActualWarehouse sub = new WmsActualWarehouse(); + sub.setParentId(parent.getActualWarehouseId()); + sub.setActualWarehouseType(4L); + sub.setSortNo(Optional.ofNullable(parent.getSortNo()).orElse(0L)); + sub.setIsEnabled(1); + sub.setSplitStatus(1); + sub.setSplitType(splitType); + sub.setDelFlag(0); + return sub; + } + @Override @Transactional(rollbackFor = Exception.class) public void mergeLocations(WmsActualWarehouseSplitBo bo) { if (bo == null || CollUtil.isEmpty(bo.getLocationIds())) { throw new ServiceException("参数不能为空"); } + List parents = baseMapper.selectList(Wrappers.lambdaQuery() .in(WmsActualWarehouse::getActualWarehouseId, bo.getLocationIds()) .eq(WmsActualWarehouse::getDelFlag, 0)); - for (WmsActualWarehouse p : parents) { - Integer st = Optional.ofNullable(p.getSplitStatus()).orElse(0); - if (st != 1) { - // 未拆分无需合并 + + for (WmsActualWarehouse parent : parents) { + Integer splitStatus = Optional.ofNullable(parent.getSplitStatus()).orElse(0); + if (splitStatus != 1) { + // 未拆分状态,无需处理 continue; } + + // 查询父库位下的所有四级子库位(包含已逻辑删除的) List children = baseMapper.selectList(Wrappers.lambdaQuery() - .eq(WmsActualWarehouse::getParentId, p.getActualWarehouseId()) + .eq(WmsActualWarehouse::getParentId, parent.getActualWarehouseId()) + .eq(WmsActualWarehouse::getActualWarehouseType, 4) .eq(WmsActualWarehouse::getDelFlag, 0)); + if (CollUtil.isEmpty(children)) { - // 无子节点,直接还原状态 - WmsActualWarehouse upd = new WmsActualWarehouse(); - upd.setActualWarehouseId(p.getActualWarehouseId()); - upd.setSplitStatus(0); - upd.setSplitType(0); - baseMapper.updateById(upd); + // 无子库位,直接还原父库位状态 + resetParentLocationStatus(parent); continue; } - // 检查子库位 isEnabled 必须为1(未占用) - boolean anyOccupied = children.stream().anyMatch(c -> !Objects.equals(c.getIsEnabled(), 1)); + + // 检查子库位是否被占用(仅检查未删除的子库位) + boolean anyOccupied = children.stream() + .filter(c -> c.getDelFlag() == 0) // 只检查启用中的子库位 + .anyMatch(c -> !Objects.equals(c.getIsEnabled(), 1)); + if (anyOccupied) { - throw new ServiceException("小库位被占用,不能合并:" + p.getActualWarehouseCode()); + throw new ServiceException("小库位被占用,不能合并:" + parent.getActualWarehouseCode()); } - // 逻辑删除小库位 - for (WmsActualWarehouse c : children) { - WmsActualWarehouse updC = new WmsActualWarehouse(); - updC.setActualWarehouseId(c.getActualWarehouseId()); - updC.setDelFlag(1); - baseMapper.updateById(updC); + + // 逻辑删除子库位(保留数据,用于后续拆分复用) + for (WmsActualWarehouse child : children) { + WmsActualWarehouse updChild = new WmsActualWarehouse(); + updChild.setActualWarehouseId(child.getActualWarehouseId()); + updChild.setDelFlag(1); // 逻辑删除 + updChild.setIsEnabled(0); // 禁用 + baseMapper.updateById(updChild); } - // 更新父状态 - WmsActualWarehouse upd = new WmsActualWarehouse(); - upd.setActualWarehouseId(p.getActualWarehouseId()); - upd.setSplitStatus(0); - upd.setSplitType(0); - baseMapper.updateById(upd); + + // 还原父库位状态 + resetParentLocationStatus(parent); } } + /** + * 重置父库位拆分状态(通用方法) + */ + private void resetParentLocationStatus(WmsActualWarehouse parent) { + WmsActualWarehouse upd = new WmsActualWarehouse(); + upd.setActualWarehouseId(parent.getActualWarehouseId()); + upd.setSplitStatus(0); // 还原为未拆分 + upd.setSplitType(0); // 清空拆分类型 + baseMapper.updateById(upd); + } }