Files
klp-oa/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java
Joshi f0547a4c8d refactor(wms): 优化库位拆分与合并逻辑
- 移除子库位启用状态的重复设置
- 改进子库位排序算法,提升性能和准确性
- 优化编码生成逻辑,支持更灵活的层级分配
- 批量处理父库位状态更新,提高执行效率
- 增强合并前的占用检查机制
- 实现子库位隐藏和父库位重置的批量操作
- 添加空值检查和异常处理,提升代码健壮性
2025-12-20 14:50:21 +08:00

769 lines
34 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.klp.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.klp.common.exception.ServiceException;
import com.klp.common.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.klp.domain.bo.WmsActualWarehouseBo;
import com.klp.domain.bo.WmsActualWarehouseHierarchyBo;
import com.klp.domain.bo.WmsActualWarehouseBatchGenerateBo;
import com.klp.domain.bo.WmsActualWarehouseSplitBo;
import com.klp.domain.vo.WmsActualWarehouseTreeVo;
import com.klp.domain.vo.WmsActualWarehouseImportVo;
import com.klp.domain.vo.WmsActualWarehouseVo;
import com.klp.domain.WmsActualWarehouse;
import com.klp.mapper.WmsActualWarehouseMapper;
import com.klp.service.IWmsActualWarehouseService;
import com.klp.domain.WmsMaterialCoil;
import com.klp.mapper.WmsMaterialCoilMapper;
import java.util.*;
import java.util.stream.Collectors;
/**
* 实际库区/库位自关联Service业务层处理
*
* @author klp
* @date 2025-11-24
*/
@RequiredArgsConstructor
@Service
public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService {
private final WmsActualWarehouseMapper baseMapper;
private final WmsMaterialCoilMapper wmsMaterialCoilMapper;
/**
* 查询实际库区/库位自关联
*/
@Override
public WmsActualWarehouseVo queryById(Long actualWarehouseId) {
return baseMapper.selectVoById(actualWarehouseId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int batchGenerateLocations(WmsActualWarehouseBatchGenerateBo bo) {
if (bo == null) {
throw new ServiceException("参数不能为空");
}
Integer rows = bo.getRowCount();
Integer cols = bo.getColumnCount();
Integer layers = bo.getLayerCount();
String prefix = bo.getPrefix();
Long parentId = bo.getParentId();
if (layers == null) {
layers = 2;
}
if (rows == null || cols == null || rows < 1 || cols < 1) {
throw new ServiceException("行/列必须为正整数");
}
if (layers < 1) {
throw new ServiceException("层必须为正整数");
}
if (StringUtils.isBlank(prefix)) {
throw new ServiceException("前缀不能为空");
}
List<String> codes = new ArrayList<>(rows * cols * layers);
for (int l = 1; l <= layers; l++) {
int rowsForLayer = (l == 2) ? Math.max(rows - 1, 1) : rows;
for (int c = 1; c <= cols; c++) {
for (int r = 1; r <= rowsForLayer; r++) {
String rStr = r < 10 ? ("0" + r) : String.valueOf(r);
String code = prefix + c + '-' + rStr + '-' + l;
codes.add(code);
}
}
}
// 去重:过滤同父级下已存在的编码
List<WmsActualWarehouse> exists = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
.eq(WmsActualWarehouse::getParentId, parentId)
.in(!codes.isEmpty(), WmsActualWarehouse::getActualWarehouseCode, codes));
Set<String> existCodes = exists.stream().map(WmsActualWarehouse::getActualWarehouseCode).collect(Collectors.toSet());
List<WmsActualWarehouse> toInsert = new ArrayList<>();
for (String code : codes) {
if (existCodes.contains(code)) {
continue;
}
WmsActualWarehouse e = new WmsActualWarehouse();
e.setParentId(parentId);
e.setActualWarehouseType(3L);
e.setActualWarehouseCode(code);
e.setActualWarehouseName(code);
e.setSortNo(0L);
e.setIsEnabled(1);
toInsert.add(e);
}
if (toInsert.isEmpty()) {
return 0;
}
boolean ok = baseMapper.insertBatch(toInsert);
if (!ok) {
throw new ServiceException("批量生成失败");
}
return toInsert.size();
}
/**
* 查询实际库区/库位自关联列表
*/
@Override
public List<WmsActualWarehouseVo> queryList(WmsActualWarehouseBo bo) {
LambdaQueryWrapper<WmsActualWarehouse> lqw = buildQueryWrapper(bo);
List<WmsActualWarehouseVo> list = baseMapper.selectVoList(lqw);
if (CollUtil.isEmpty(list)) {
return list;
}
// 如果当前查询的是某二级父节点下的三级库位,需要将被拆分的大库位替换为其两个子库位
if (bo.getParentId() != null) {
List<Long> splitParentIds = list.stream()
.filter(v -> Optional.ofNullable(v.getSplitStatus()).orElse(0) == 1)
.map(WmsActualWarehouseVo::getActualWarehouseId)
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(splitParentIds)) {
List<WmsActualWarehouseVo> children = baseMapper.selectVoList(
Wrappers.<WmsActualWarehouse>lambdaQuery()
.in(WmsActualWarehouse::getParentId, splitParentIds)
.eq(WmsActualWarehouse::getDelFlag, 0)
.orderByAsc(WmsActualWarehouse::getActualWarehouseCode, WmsActualWarehouse::getActualWarehouseId)
);
Map<Long, List<WmsActualWarehouseVo>> childrenMap = children.stream()
.collect(Collectors.groupingBy(WmsActualWarehouseVo::getParentId, LinkedHashMap::new, Collectors.toList()));
List<WmsActualWarehouseVo> expanded = new ArrayList<>(list.size() + children.size());
for (WmsActualWarehouseVo v : list) {
if (Optional.ofNullable(v.getSplitStatus()).orElse(0) == 1) {
List<WmsActualWarehouseVo> ch = childrenMap.get(v.getActualWarehouseId());
if (CollUtil.isNotEmpty(ch)) {
expanded.addAll(ch);
continue;
}
}
expanded.add(v);
}
list = expanded;
}
}
// 仅对被占用的位置isEnabled=0补充钢卷信息
List<Long> occupiedAwIds = list.stream()
.filter(it -> it.getIsEnabled() != null && it.getIsEnabled() == 0)
.map(WmsActualWarehouseVo::getActualWarehouseId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (CollUtil.isEmpty(occupiedAwIds)) {
return list;
}
// 查询当前在库(del_flag=0, status=0)并且占用这些库位的钢卷,仅选择必要列
List<WmsMaterialCoil> coils = wmsMaterialCoilMapper.selectList(
Wrappers.<WmsMaterialCoil>lambdaQuery()
.select(
WmsMaterialCoil::getActualWarehouseId,
WmsMaterialCoil::getCoilId,
WmsMaterialCoil::getEnterCoilNo,
WmsMaterialCoil::getCurrentCoilNo,
WmsMaterialCoil::getSupplierCoilNo
)
.in(WmsMaterialCoil::getActualWarehouseId, occupiedAwIds)
.eq(WmsMaterialCoil::getDelFlag, 0)
.eq(WmsMaterialCoil::getStatus, 0)
);
if (CollUtil.isEmpty(coils)) {
return list;
}
// 同一库位若有多条记录,选择最新一条(按更新顺序无字段,这里按主键最大)
Map<Long, WmsMaterialCoil> coilByAwId = coils.stream()
.collect(Collectors.toMap(
WmsMaterialCoil::getActualWarehouseId,
c -> c,
(a, b) -> a.getCoilId() != null && b.getCoilId() != null && a.getCoilId() > b.getCoilId() ? a : b
));
list.forEach(it -> {
if (it.getIsEnabled() != null && it.getIsEnabled() == 0) {
WmsMaterialCoil c = coilByAwId.get(it.getActualWarehouseId());
if (c != null) {
it.setEnterCoilNo(c.getEnterCoilNo());
it.setCurrentCoilNo(c.getCurrentCoilNo());
it.setSupplierCoilNo(c.getSupplierCoilNo());
}
}
});
return list;
}
@Override
public List<WmsActualWarehouseTreeVo> queryTree(WmsActualWarehouseBo bo) {
if (bo == null) {
bo = new WmsActualWarehouseBo();
}
LambdaQueryWrapper<WmsActualWarehouse> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StringUtils.isNotBlank(bo.getActualWarehouseCode()), WmsActualWarehouse::getActualWarehouseCode, bo.getActualWarehouseCode());
wrapper.like(StringUtils.isNotBlank(bo.getActualWarehouseName()), WmsActualWarehouse::getActualWarehouseName, bo.getActualWarehouseName());
wrapper.eq(bo.getActualWarehouseType() != null, WmsActualWarehouse::getActualWarehouseType, bo.getActualWarehouseType());
wrapper.eq(bo.getIsEnabled() != null, WmsActualWarehouse::getIsEnabled, bo.getIsEnabled());
wrapper.orderByAsc(WmsActualWarehouse::getSortNo, WmsActualWarehouse::getActualWarehouseId);
List<WmsActualWarehouseVo> flatList = baseMapper.selectVoList(wrapper);
Map<Long, WmsActualWarehouseTreeVo> nodeMap = new LinkedHashMap<>();
flatList.forEach(item -> {
WmsActualWarehouseTreeVo node = new WmsActualWarehouseTreeVo();
BeanUtil.copyProperties(item, node);
nodeMap.put(node.getActualWarehouseId(), node);
});
List<WmsActualWarehouseTreeVo> roots = new ArrayList<>();
nodeMap.values().forEach(node -> {
Long parentId = Optional.ofNullable(node.getParentId()).orElse(0L);
if (parentId == 0 || !nodeMap.containsKey(parentId)) {
roots.add(node);
} else {
nodeMap.get(parentId).getChildren().add(node);
}
});
return roots;
}
@Override
public List<WmsActualWarehouseTreeVo> queryTreeExcludeLevelThree(WmsActualWarehouseBo bo) {
if (bo == null) {
bo = new WmsActualWarehouseBo();
}
// 设置查询条件排除三级节点actualWarehouseType=3
LambdaQueryWrapper<WmsActualWarehouse> wrapper = Wrappers.lambdaQuery();
wrapper.eq(StringUtils.isNotBlank(bo.getActualWarehouseCode()), WmsActualWarehouse::getActualWarehouseCode, bo.getActualWarehouseCode());
wrapper.like(StringUtils.isNotBlank(bo.getActualWarehouseName()), WmsActualWarehouse::getActualWarehouseName, bo.getActualWarehouseName());
wrapper.eq(bo.getActualWarehouseType() != null, WmsActualWarehouse::getActualWarehouseType, bo.getActualWarehouseType());
wrapper.eq(bo.getIsEnabled() != null, WmsActualWarehouse::getIsEnabled, bo.getIsEnabled());
// 排除三级节点类型为3的节点
wrapper.ne(WmsActualWarehouse::getActualWarehouseType, 3);
// 四级节点也排除
wrapper.ne(WmsActualWarehouse::getActualWarehouseType, 4);
wrapper.orderByAsc(WmsActualWarehouse::getSortNo, WmsActualWarehouse::getActualWarehouseId);
List<WmsActualWarehouseVo> flatList = baseMapper.selectVoList(wrapper);
Map<Long, WmsActualWarehouseTreeVo> nodeMap = new LinkedHashMap<>();
flatList.forEach(item -> {
WmsActualWarehouseTreeVo node = new WmsActualWarehouseTreeVo();
BeanUtil.copyProperties(item, node);
nodeMap.put(node.getActualWarehouseId(), node);
});
List<WmsActualWarehouseTreeVo> roots = new ArrayList<>();
nodeMap.values().forEach(node -> {
Long parentId = Optional.ofNullable(node.getParentId()).orElse(0L);
if (parentId == 0 || !nodeMap.containsKey(parentId)) {
roots.add(node);
} else {
nodeMap.get(parentId).getChildren().add(node);
}
});
return roots;
}
private LambdaQueryWrapper<WmsActualWarehouse> buildQueryWrapper(WmsActualWarehouseBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<WmsActualWarehouse> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getParentId() != null, WmsActualWarehouse::getParentId, bo.getParentId());
lqw.eq(StringUtils.isNotBlank(bo.getActualWarehouseCode()), WmsActualWarehouse::getActualWarehouseCode, bo.getActualWarehouseCode());
lqw.like(StringUtils.isNotBlank(bo.getActualWarehouseName()), WmsActualWarehouse::getActualWarehouseName, bo.getActualWarehouseName());
lqw.eq(bo.getActualWarehouseType() != null, WmsActualWarehouse::getActualWarehouseType, bo.getActualWarehouseType());
lqw.eq(bo.getSortNo() != null, WmsActualWarehouse::getSortNo, bo.getSortNo());
lqw.eq(bo.getIsEnabled() != null, WmsActualWarehouse::getIsEnabled, bo.getIsEnabled());
return lqw;
}
/**
* 新增实际库区/库位自关联
*/
@Override
public Boolean insertByBo(WmsActualWarehouseBo bo) {
WmsActualWarehouse add = BeanUtil.toBean(bo, WmsActualWarehouse.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setActualWarehouseId(add.getActualWarehouseId());
}
return flag;
}
/**
* 修改实际库区/库位自关联
*/
@Override
public Boolean updateByBo(WmsActualWarehouseBo bo) {
WmsActualWarehouse update = BeanUtil.toBean(bo, WmsActualWarehouse.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public List<Long> createHierarchy(WmsActualWarehouseHierarchyBo bo) {
if (bo.getLevels() == null || bo.getLevels().isEmpty()) {
throw new ServiceException("层级数据不能为空");
}
List<WmsActualWarehouseHierarchyBo.HierarchyLevel> sortedLevels = bo.getLevels().stream()
.sorted(Comparator.comparing(WmsActualWarehouseHierarchyBo.HierarchyLevel::getLevel))
.collect(Collectors.toList());
Long parentId = 0L;
List<Long> createdIds = new ArrayList<>();
for (WmsActualWarehouseHierarchyBo.HierarchyLevel level : sortedLevels) {
Integer levelValue = level.getLevel();
if (levelValue == null || levelValue < 1 || levelValue > 3) {
throw new ServiceException("层级必须在1-3之间");
}
if (level.getActualWarehouseId() != null) {
WmsActualWarehouse existing = baseMapper.selectById(level.getActualWarehouseId());
if (existing == null) {
throw new ServiceException("指定的节点不存在:" + level.getActualWarehouseId());
}
if (!Objects.equals(Optional.ofNullable(existing.getParentId()).orElse(0L), parentId)) {
throw new ServiceException("节点不属于当前父级,无法复用");
}
parentId = existing.getActualWarehouseId();
continue;
}
if (StringUtils.isBlank(level.getActualWarehouseCode()) || StringUtils.isBlank(level.getActualWarehouseName())) {
throw new ServiceException("编码与名称不能为空");
}
WmsActualWarehouse duplicate = baseMapper.selectOne(Wrappers.<WmsActualWarehouse>lambdaQuery()
.eq(WmsActualWarehouse::getParentId, parentId)
.and(wrapper -> wrapper.eq(WmsActualWarehouse::getActualWarehouseCode, level.getActualWarehouseCode())
.or()
.eq(WmsActualWarehouse::getActualWarehouseName, level.getActualWarehouseName())));
if (duplicate != null) {
parentId = duplicate.getActualWarehouseId();
continue;
}
WmsActualWarehouse entity = new WmsActualWarehouse();
entity.setParentId(parentId);
entity.setActualWarehouseType(levelValue.longValue());
entity.setActualWarehouseCode(level.getActualWarehouseCode());
entity.setActualWarehouseName(level.getActualWarehouseName());
entity.setSortNo(Optional.ofNullable(level.getSortNo()).orElse(0L));
entity.setIsEnabled(Optional.ofNullable(level.getIsEnabled()).orElse(1));
entity.setRemark(level.getRemark());
baseMapper.insert(entity);
parentId = entity.getActualWarehouseId();
createdIds.add(parentId);
}
return createdIds;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void importHierarchy(List<WmsActualWarehouseImportVo> importList) {
if (CollUtil.isEmpty(importList)) {
throw new ServiceException("导入数据不能为空");
}
for (WmsActualWarehouseImportVo row : importList) {
List<WmsActualWarehouseHierarchyBo.HierarchyLevel> levels = new ArrayList<>();
appendLevel(levels, 1, row.getLevelOneCode(), row.getLevelOneName(), row.getLevelOneSort());
appendLevel(levels, 2, row.getLevelTwoCode(), row.getLevelTwoName(), row.getLevelTwoSort());
appendLevel(levels, 3, row.getLevelThreeCode(), row.getLevelThreeName(), row.getLevelThreeSort());
if (levels.isEmpty()) {
continue;
}
WmsActualWarehouseHierarchyBo bo = new WmsActualWarehouseHierarchyBo();
bo.setLevels(levels);
createHierarchy(bo);
}
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(WmsActualWarehouse entity) {
//TODO 做一些数据校验,如唯一约束
}
private void appendLevel(List<WmsActualWarehouseHierarchyBo.HierarchyLevel> levels,
int level,
String code,
String name,
Long sortNo) {
if (StringUtils.isBlank(code) || StringUtils.isBlank(name)) {
return;
}
WmsActualWarehouseHierarchyBo.HierarchyLevel item = new WmsActualWarehouseHierarchyBo.HierarchyLevel();
item.setLevel(level);
item.setActualWarehouseCode(code.trim());
item.setActualWarehouseName(name.trim());
item.setSortNo(Optional.ofNullable(sortNo).orElse(0L));
item.setIsEnabled(1);
levels.add(item);
}
/**
* 批量删除实际库区/库位自关联
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void splitLocations(WmsActualWarehouseSplitBo bo) {
if (bo == null) {
throw new ServiceException("参数不能为空");
}
// 参数验证
String columnFlag = bo.getColumnFlag();
if (StringUtils.isBlank(columnFlag)) {
throw new ServiceException("列标识不能为空");
}
int splitType = Optional.ofNullable(bo.getSplitType()).orElse(0);
List<Long> splitIds = Optional.ofNullable(bo.getSplitIds()).orElse(new ArrayList<>());
if (splitIds.isEmpty()) {
throw new ServiceException("待拆分库位ID列表不能为空");
}
// 根据列标识查询该列的所有三级库位
List<WmsActualWarehouse> columnLocations = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
.like(WmsActualWarehouse::getActualWarehouseCode, columnFlag)
.eq(WmsActualWarehouse::getDelFlag, 0)
.eq(WmsActualWarehouse::getActualWarehouseType, 3)
.orderByAsc(WmsActualWarehouse::getActualWarehouseCode));
if (CollUtil.isEmpty(columnLocations)) {
throw new ServiceException("未找到列标识为 " + columnFlag + " 的库位");
}
// 分离需要拆分的库位和剩余库位
List<WmsActualWarehouse> splitLocations = new ArrayList<>();
List<WmsActualWarehouse> remainingLocations = new ArrayList<>();
for (WmsActualWarehouse location : columnLocations) {
if (splitIds.contains(location.getActualWarehouseId())) {
splitLocations.add(location);
} else {
remainingLocations.add(location);
}
}
// 存储需要插入/更新的子库位
List<WmsActualWarehouse> toInsert = new ArrayList<>();
List<WmsActualWarehouse> toUpdate = new ArrayList<>();
// 1. 处理需要拆分的库位每个拆分为2个子库位
for (WmsActualWarehouse location : splitLocations) {
// 先查询该父库位下是否存在已逻辑删除的子库位(合并后保留的)
List<WmsActualWarehouse> existingChildren = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
.eq(WmsActualWarehouse::getParentId, location.getActualWarehouseId())
.eq(WmsActualWarehouse::getActualWarehouseType, 4)
.eq(WmsActualWarehouse::getDelFlag, 1)); // 查询已逻辑删除的子库位
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);
}
}
// 2. 处理剩余库位每个拆分为1个子库位
for (WmsActualWarehouse remainingLocation : remainingLocations) {
// 先查询是否存在已逻辑删除的子库位
List<WmsActualWarehouse> existingChildren = baseMapper.selectList(Wrappers.<WmsActualWarehouse>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);
}
}
// 3. 验证总数
int expectedSplitSub = splitLocations.size() * 2;
int expectedRemainingSub = remainingLocations.size() * 1;
int expectedTotal = expectedSplitSub + expectedRemainingSub;
// 实际总数 = 新增数 + 复用数
int actualTotal = toInsert.size() + toUpdate.size();
if (actualTotal != expectedTotal) {
throw new ServiceException(String.format(
"子库位数量不匹配,期望%d个实际新增%d个+复用%d个=%d个",
expectedTotal, toInsert.size(), toUpdate.size(), actualTotal));
}
// 4. 批量插入新子库位
if (!toInsert.isEmpty()) {
boolean insertOk = baseMapper.insertBatch(toInsert);
if (!insertOk) {
throw new ServiceException("新增子库位失败");
}
}
// 5. 批量更新复用的子库位(恢复状态)
if (!toUpdate.isEmpty()) {
for (WmsActualWarehouse child : toUpdate) {
baseMapper.updateById(child);
}
}
// 6. 统一生成/更新子库位编码(包含新增和复用的)
List<WmsActualWarehouse> allSubLocations = new ArrayList<>();
allSubLocations.addAll(toInsert);
allSubLocations.addAll(toUpdate);
if (!allSubLocations.isEmpty()) {
// 按父库位在columnLocations中的顺序排序
Map<Long, Integer> 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<WmsActualWarehouse> 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<WmsActualWarehouse> 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())) {
throw new ServiceException("参数不能为空");
}
// 批量查询父库位
List<WmsActualWarehouse> parents = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
.in(WmsActualWarehouse::getActualWarehouseId, bo.getLocationIds())
.eq(WmsActualWarehouse::getDelFlag, 0));
if (CollUtil.isEmpty(parents)) {
return;
}
// 过滤出已拆分的父库位
List<WmsActualWarehouse> splitParents = parents.stream()
.filter(p -> Optional.ofNullable(p.getSplitStatus()).orElse(0) == 1)
.collect(Collectors.toList());
if (CollUtil.isEmpty(splitParents)) {
return;
}
// 批量查询所有子库位
List<Long> splitParentIds = splitParents.stream()
.map(WmsActualWarehouse::getActualWarehouseId)
.collect(Collectors.toList());
List<WmsActualWarehouse> allChildren = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
.in(WmsActualWarehouse::getParentId, splitParentIds)
.eq(WmsActualWarehouse::getActualWarehouseType, 4)
.eq(WmsActualWarehouse::getDelFlag, 0));
// 按父ID分组子库位
Map<Long, List<WmsActualWarehouse>> childrenByParent = allChildren.stream()
.collect(Collectors.groupingBy(WmsActualWarehouse::getParentId));
// 检查是否有被占用的子库位
List<WmsActualWarehouse> occupiedChildren = allChildren.stream()
.filter(c -> !Objects.equals(c.getIsEnabled(), 1))
.collect(Collectors.toList());
if (!occupiedChildren.isEmpty()) {
// 找到被占用子库位的父库位名称
Set<Long> occupiedParentIds = occupiedChildren.stream()
.map(WmsActualWarehouse::getParentId)
.collect(Collectors.toSet());
List<String> occupiedParentCodes = splitParents.stream()
.filter(p -> occupiedParentIds.contains(p.getActualWarehouseId()))
.map(WmsActualWarehouse::getActualWarehouseCode)
.collect(Collectors.toList());
throw new ServiceException("以下库位的小库位被占用,不能合并:" + String.join(", ", occupiedParentCodes));
}
// 准备批量更新操作
List<WmsActualWarehouse> childrenToHide = new ArrayList<>();
List<WmsActualWarehouse> parentsToReset = new ArrayList<>();
for (WmsActualWarehouse parent : splitParents) {
List<WmsActualWarehouse> 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);
continue;
}
// 准备隐藏子库位
for (WmsActualWarehouse child : children) {
WmsActualWarehouse childUpdate = new WmsActualWarehouse();
childUpdate.setActualWarehouseId(child.getActualWarehouseId());
childUpdate.setDelFlag(1); // 逻辑删除(隐藏)
childrenToHide.add(childUpdate);
}
// 准备重置父库位状态
WmsActualWarehouse parentUpdate = new WmsActualWarehouse();
parentUpdate.setActualWarehouseId(parent.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);
}
}
}
/**
* 重置父库位拆分状态(通用方法)
*/
private void resetParentLocationStatus(WmsActualWarehouse parent) {
WmsActualWarehouse upd = new WmsActualWarehouse();
upd.setActualWarehouseId(parent.getActualWarehouseId());
upd.setSplitStatus(0); // 还原为未拆分
upd.setSplitType(0); // 清空拆分类型
baseMapper.updateById(upd);
}
}