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 9de5a724..4312ea4f 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,23 +434,107 @@ public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService } int splitType = Optional.ofNullable(bo.getSplitType()).orElse(0); - List splitIds = Optional.ofNullable(bo.getSplitIds()).orElse(new ArrayList<>()); + List Ids = Optional.ofNullable(bo.getSplitIds()).orElse(new ArrayList<>()); + + // 合并所有待拆分的ID + Set splitIds = new HashSet<>(); + splitIds.addAll(Ids); 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)) { throw new ServiceException("未找到列标识为 " + columnFlag + " 的库位"); } + // 检查是否已经有子库位存在(包括被删除的) + boolean hasExistingChildren = false; + for (WmsActualWarehouse location : columnLocations) { + List existingChildren = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(WmsActualWarehouse::getParentId, location.getActualWarehouseId()) + .eq(WmsActualWarehouse::getActualWarehouseType, 4)); // 四级子库位 + if (CollUtil.isNotEmpty(existingChildren)) { + hasExistingChildren = true; + break; + } + } + + if (hasExistingChildren) { + // 如果已经有子库位,执行复活逻辑 + reviveExistingSubLocations(columnLocations, splitIds, splitType); + } else { + // 如果没有子库位,执行创建逻辑 + createNewSubLocationsWithOriginalLogic(columnLocations, splitIds, splitType, columnFlag); + } + + // 更新该列所有被拆分库位的状态 + for (WmsActualWarehouse location : columnLocations) { + WmsActualWarehouse upd = new WmsActualWarehouse(); + upd.setActualWarehouseId(location.getActualWarehouseId()); + upd.setSplitStatus(1); + upd.setSplitType(splitType); + baseMapper.updateById(upd); + } + } + + /** + * 复活已存在的子库位 + */ + private void reviveExistingSubLocations(List columnLocations, Set splitIds, Integer splitType) { + for (WmsActualWarehouse location : columnLocations) { + boolean isSplitLocation = splitIds.contains(location.getActualWarehouseId()); + + // 查询该库位下所有子库位(包括已删除的) + List allChildren = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(WmsActualWarehouse::getParentId, location.getActualWarehouseId()) + .eq(WmsActualWarehouse::getActualWarehouseType, 4) // 四级子库位 + .orderByAsc(WmsActualWarehouse::getActualWarehouseId)); + + if (CollUtil.isNotEmpty(allChildren)) { + // 根据是否为拆分库位决定需要复活的子库位数量 + int requiredCount = isSplitLocation ? 2 : 1; + + // 复活前N个子库位 + for (int i = 0; i < Math.min(requiredCount, allChildren.size()); i++) { + WmsActualWarehouse child = allChildren.get(i); + if (child.getDelFlag() == 1) { // 只处理已删除的子库位 + WmsActualWarehouse childUpdate = new WmsActualWarehouse(); + childUpdate.setActualWarehouseId(child.getActualWarehouseId()); + childUpdate.setDelFlag(0); + childUpdate.setSplitStatus(1); + childUpdate.setSplitType(splitType); + baseMapper.updateById(childUpdate); + } + } + + // 如果子库位数量超过需要的数量,隐藏多余的 + if (allChildren.size() > requiredCount) { + for (int i = requiredCount; i < allChildren.size(); i++) { + WmsActualWarehouse child = allChildren.get(i); + if (child.getDelFlag() == 0) { // 只处理未删除的子库位 + WmsActualWarehouse childUpdate = new WmsActualWarehouse(); + childUpdate.setActualWarehouseId(child.getActualWarehouseId()); + childUpdate.setDelFlag(1); + baseMapper.updateById(childUpdate); + } + } + } + } + } + } + + /** + * 使用逻辑创建新的子库位 + */ + private void createNewSubLocationsWithOriginalLogic(List columnLocations, Set splitIds, Integer splitType, String columnFlag) { // 分离需要拆分的库位和剩余库位 List splitLocations = new ArrayList<>(); List remainingLocations = new ArrayList<>(); @@ -463,306 +547,173 @@ public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService } } - // 存储需要插入/更新的子库位 + // 第一步:先创建所有子库位(不设置编码) List toInsert = new ArrayList<>(); - List toUpdate = new ArrayList<>(); // 1. 处理需要拆分的库位(每个拆分为2个子库位) for (WmsActualWarehouse location : splitLocations) { - // 先查询该父库位下是否存在已逻辑删除的子库位(合并后保留的) - List existingChildren = baseMapper.selectList(Wrappers.lambdaQuery() - .eq(WmsActualWarehouse::getParentId, location.getActualWarehouseId()) - .eq(WmsActualWarehouse::getActualWarehouseType, 4) - .eq(WmsActualWarehouse::getDelFlag, 1)); // 查询已逻辑删除的子库位 + // 生成第一个子库位 + 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); - if (CollUtil.isNotEmpty(existingChildren) && existingChildren.size() == 2) { - // 复用原有子库位:恢复启用状态,更新拆分类型 - for (WmsActualWarehouse child : existingChildren) { - child.setDelFlag(0); // 恢复未删除 - 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); - } + // 生成第二个子库位 + 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); } - // 2. 处理剩余库位(每个拆分为1个子库位) + // 2. 处理剩余库位(每个拆分为1个子库位,保持原层级) for (WmsActualWarehouse remainingLocation : remainingLocations) { - // 先查询是否存在已逻辑删除的子库位 - List existingChildren = baseMapper.selectList(Wrappers.lambdaQuery() - .eq(WmsActualWarehouse::getParentId, remainingLocation.getActualWarehouseId()) - .eq(WmsActualWarehouse::getActualWarehouseType, 4) - .eq(WmsActualWarehouse::getDelFlag, 1)); - - 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); - } + // 生成剩余库位的子库位 + 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); } // 3. 验证总数 - int expectedSplitSub = splitLocations.size() * 2; - int expectedRemainingSub = remainingLocations.size() * 1; - int expectedTotal = expectedSplitSub + expectedRemainingSub; - // 实际总数 = 新增数 + 复用数 - int actualTotal = toInsert.size() + toUpdate.size(); + int expectedSplitSubLocations = splitLocations.size() * 2; + int expectedRemainingSubLocations = remainingLocations.size() * 1; + int expectedTotalSubLocations = expectedSplitSubLocations + expectedRemainingSubLocations; + int actualTotalSubLocations = toInsert.size(); - if (actualTotal != expectedTotal) { + if (actualTotalSubLocations != expectedTotalSubLocations) { throw new ServiceException(String.format( - "子库位数量不匹配,期望%d个,实际新增%d个+复用%d个=%d个", - expectedTotal, toInsert.size(), toUpdate.size(), actualTotal)); + "子库位生成数量不匹配,期望%d个(拆分库位:%d个→%d个,剩余库位:%d个→%d个),实际生成%d个", + expectedTotalSubLocations, + splitLocations.size(), expectedSplitSubLocations, + remainingLocations.size(), expectedRemainingSubLocations, + actualTotalSubLocations + )); } - // 4. 批量插入新子库位 + // 4. 批量插入子库位(先插入获取ID) if (!toInsert.isEmpty()) { - boolean insertOk = baseMapper.insertBatch(toInsert); - if (!insertOk) { + boolean ok = baseMapper.insertBatch(toInsert); + if (!ok) { throw new ServiceException("新增子库位失败"); } } - // 5. 批量更新复用的子库位(恢复状态) + // 第二步:重新生成编码 + 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. 批量更新编码 if (!toUpdate.isEmpty()) { - for (WmsActualWarehouse child : toUpdate) { - baseMapper.updateById(child); + for (WmsActualWarehouse item : toUpdate) { + baseMapper.updateById(item); } } - - // 6. 统一生成/更新子库位编码(包含新增和复用的) - List allSubLocations = new ArrayList<>(); - allSubLocations.addAll(toInsert); - allSubLocations.addAll(toUpdate); - - if (!allSubLocations.isEmpty()) { - // 按父库位在columnLocations中的顺序排序 - Map parentOrderMap = new HashMap<>(); - for (int i = 0; i < columnLocations.size(); i++) { - parentOrderMap.put(columnLocations.get(i).getActualWarehouseId(), i); - } - - allSubLocations.sort((a, b) -> { - int orderA = parentOrderMap.getOrDefault(a.getParentId(), Integer.MAX_VALUE); - int orderB = parentOrderMap.getOrDefault(b.getParentId(), Integer.MAX_VALUE); - if (orderA != orderB) { - return Integer.compare(orderA, orderB); - } - // 同一父库位下,按层级排序(假设层级1在前,层级2在后) - return Long.compare(a.getActualWarehouseId(), b.getActualWarehouseId()); - }); - - // 生成规范编码 - String prefix = columnFlag; - List codeToUpdate = new ArrayList<>(); - - int sequenceNum = 1; - for (int i = 0; i < allSubLocations.size(); i++) { - WmsActualWarehouse sub = allSubLocations.get(i); - - // 判断是第一层还是第二层 - // 如果是拆分库位的子库位,按顺序分配层级 - // 如果是剩余库位的子库位,保持原层级 - Long parentId = sub.getParentId(); - boolean isFromSplitLocation = splitLocations.stream() - .anyMatch(loc -> loc.getActualWarehouseId().equals(parentId)); - - int layer; - if (isFromSplitLocation) { - // 拆分库位:第一个子库位是层级1,第二个是层级2 - final int currentIndex = i; // 创建一个有效的final变量 - long sameParentCount = allSubLocations.stream() - .filter(s -> s.getParentId().equals(parentId)) - .filter(s -> allSubLocations.indexOf(s) <= currentIndex) - .count(); - layer = (int) ((sameParentCount - 1) % 2) + 1; - } else { - // 剩余库位:保持原层级 - WmsActualWarehouse parent = columnLocations.stream() - .filter(loc -> loc.getActualWarehouseId().equals(parentId)) - .findFirst().orElse(null); - if (parent != null) { - String[] parts = parent.getActualWarehouseCode().split("-"); - layer = parts.length >= 3 ? Integer.parseInt(parts[2]) : 1; - } else { - layer = 1; - } - } - - String newCode = String.format("%s-X%02d-%d", prefix, sequenceNum, layer); - sub.setActualWarehouseCode(newCode); - sub.setActualWarehouseName(newCode); - codeToUpdate.add(sub); - - // 如果是拆分库位的第二个子库位,或者是剩余库位的子库位,序号递增 - if (!isFromSplitLocation || layer == 2) { - sequenceNum++; - } - } - - // 批量更新编码 - for (WmsActualWarehouse sub : codeToUpdate) { - baseMapper.updateById(sub); - } - } - - // 7. 批量更新父库位拆分状态 - List parentUpdates = new ArrayList<>(); - for (WmsActualWarehouse location : columnLocations) { - WmsActualWarehouse upd = new WmsActualWarehouse(); - upd.setActualWarehouseId(location.getActualWarehouseId()); - upd.setSplitStatus(1); - upd.setSplitType(splitType); - parentUpdates.add(upd); - } - - for (WmsActualWarehouse upd : parentUpdates) { - baseMapper.updateById(upd); - } - } - - /** - * 创建子库位基础对象(通用方法) - */ - 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())) { + if (bo == null) { throw new ServiceException("参数不能为空"); } - // 批量查询父库位 - List parents = baseMapper.selectList(Wrappers.lambdaQuery() - .in(WmsActualWarehouse::getActualWarehouseId, bo.getLocationIds()) - .eq(WmsActualWarehouse::getDelFlag, 0)); - - if (CollUtil.isEmpty(parents)) { - return; + // 获取列标识 + String columnFlag = bo.getColumnFlag(); + if (StringUtils.isBlank(columnFlag)) { + throw new ServiceException("列标识不能为空"); } - // 过滤出已拆分的父库位 - List splitParents = parents.stream() - .filter(p -> Optional.ofNullable(p.getSplitStatus()).orElse(0) == 1) - .collect(Collectors.toList()); + // 根据列标识查询该列的所有三级库位 + List columnLocations = baseMapper.selectList(Wrappers.lambdaQuery() + .like(WmsActualWarehouse::getActualWarehouseCode, columnFlag) + .eq(WmsActualWarehouse::getDelFlag, 0) + .eq(WmsActualWarehouse::getActualWarehouseType, 3) // 只查询三级库位 + .orderByAsc(WmsActualWarehouse::getActualWarehouseCode)); - if (CollUtil.isEmpty(splitParents)) { - return; + if (CollUtil.isEmpty(columnLocations)) { + throw new ServiceException("未找到列标识为 " + columnFlag + " 的库位"); } - // 批量查询所有子库位 - List splitParentIds = splitParents.stream() - .map(WmsActualWarehouse::getActualWarehouseId) - .collect(Collectors.toList()); - - List allChildren = baseMapper.selectList(Wrappers.lambdaQuery() - .in(WmsActualWarehouse::getParentId, splitParentIds) - .eq(WmsActualWarehouse::getActualWarehouseType, 4) - .eq(WmsActualWarehouse::getDelFlag, 0)); - - // 按父ID分组子库位 - Map> childrenByParent = allChildren.stream() - .collect(Collectors.groupingBy(WmsActualWarehouse::getParentId)); - - // 检查是否有被占用的子库位 - List occupiedChildren = allChildren.stream() - .filter(c -> !Objects.equals(c.getIsEnabled(), 1)) - .collect(Collectors.toList()); - - if (!occupiedChildren.isEmpty()) { - // 找到被占用子库位的父库位名称 - Set occupiedParentIds = occupiedChildren.stream() - .map(WmsActualWarehouse::getParentId) - .collect(Collectors.toSet()); - - List occupiedParentCodes = splitParents.stream() - .filter(p -> occupiedParentIds.contains(p.getActualWarehouseId())) - .map(WmsActualWarehouse::getActualWarehouseCode) - .collect(Collectors.toList()); - - throw new ServiceException("以下库位的小库位被占用,不能合并:" + String.join(", ", occupiedParentCodes)); - } - - // 准备批量更新操作 - List childrenToHide = new ArrayList<>(); - List parentsToReset = new ArrayList<>(); - - for (WmsActualWarehouse parent : splitParents) { - List children = childrenByParent.get(parent.getActualWarehouseId()); - - if (CollUtil.isEmpty(children)) { - // 无子库位,直接重置父库位状态 - WmsActualWarehouse parentUpdate = new WmsActualWarehouse(); - parentUpdate.setActualWarehouseId(parent.getActualWarehouseId()); - parentUpdate.setSplitStatus(0); - parentUpdate.setSplitType(0); - parentsToReset.add(parentUpdate); + // 合并操作:隐藏子库位 + for (WmsActualWarehouse location : columnLocations) { + Integer currentSplitStatus = Optional.ofNullable(location.getSplitStatus()).orElse(0); + if (currentSplitStatus != 1) { + // 未拆分的库位无需合并 continue; } - // 准备隐藏子库位 - for (WmsActualWarehouse child : children) { - WmsActualWarehouse childUpdate = new WmsActualWarehouse(); - childUpdate.setActualWarehouseId(child.getActualWarehouseId()); - childUpdate.setDelFlag(1); // 逻辑删除(隐藏) - childrenToHide.add(childUpdate); + // 查询该库位下所有子库位(包括已删除的) + List allChildren = baseMapper.selectList(Wrappers.lambdaQuery() + .eq(WmsActualWarehouse::getParentId, location.getActualWarehouseId()) + .eq(WmsActualWarehouse::getActualWarehouseType, 4)); // 四级子库位 + + if (CollUtil.isNotEmpty(allChildren)) { + // 检查子库位是否被占用(只检查未删除的子库位) + List activeChildren = allChildren.stream() + .filter(c -> c.getDelFlag() == 0) + .collect(Collectors.toList()); + + boolean anyOccupied = activeChildren.stream() + .anyMatch(c -> !Objects.equals(c.getIsEnabled(), 1)); + if (anyOccupied) { + throw new ServiceException("子库位被占用,不能合并:" + location.getActualWarehouseCode()); + } + + // 隐藏所有子库位(设置delFlag=1) + for (WmsActualWarehouse child : allChildren) { + if (child.getDelFlag() == 0) { // 只处理未删除的子库位 + WmsActualWarehouse childUpdate = new WmsActualWarehouse(); + childUpdate.setActualWarehouseId(child.getActualWarehouseId()); + childUpdate.setDelFlag(2); + baseMapper.updateById(childUpdate); + } + } } - // 准备重置父库位状态 + // 更新父库位状态为未拆分 WmsActualWarehouse parentUpdate = new WmsActualWarehouse(); - parentUpdate.setActualWarehouseId(parent.getActualWarehouseId()); + parentUpdate.setActualWarehouseId(location.getActualWarehouseId()); parentUpdate.setSplitStatus(0); parentUpdate.setSplitType(0); - parentsToReset.add(parentUpdate); - } - - // 批量执行更新操作 - if (!childrenToHide.isEmpty()) { - for (WmsActualWarehouse child : childrenToHide) { - baseMapper.updateById(child); - } - } - - if (!parentsToReset.isEmpty()) { - for (WmsActualWarehouse parent : parentsToReset) { - baseMapper.updateById(parent); - } + baseMapper.updateById(parentUpdate); } } - /** - * 重置父库位拆分状态(通用方法) - */ - private void resetParentLocationStatus(WmsActualWarehouse parent) { - WmsActualWarehouse upd = new WmsActualWarehouse(); - upd.setActualWarehouseId(parent.getActualWarehouseId()); - upd.setSplitStatus(0); // 还原为未拆分 - upd.setSplitType(0); // 清空拆分类型 - baseMapper.updateById(upd); - } }