Files
klp-oa/klp-wms/src/main/java/com/klp/service/impl/WmsActualWarehouseServiceImpl.java

670 lines
29 KiB
Java
Raw Normal View History

package com.klp.service.impl;
import cn.hutool.core.bean.BeanUtil;
2025-11-25 01:13:26 +08:00
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
2025-11-25 01:13:26 +08:00
import com.klp.common.exception.ServiceException;
import com.klp.common.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
2025-11-25 01:13:26 +08:00
import org.springframework.transaction.annotation.Transactional;
import com.klp.domain.bo.WmsActualWarehouseBo;
2025-11-25 01:13:26 +08:00
import com.klp.domain.bo.WmsActualWarehouseHierarchyBo;
import com.klp.domain.bo.WmsActualWarehouseBatchGenerateBo;
import com.klp.domain.bo.WmsActualWarehouseSplitBo;
2025-11-25 01:13:26 +08:00
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;
2025-11-25 01:13:26 +08:00
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;
}
2025-11-25 01:13:26 +08:00
@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;
}
2025-11-25 01:13:26 +08:00
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;
}
2025-11-25 01:13:26 +08:00
@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 做一些数据校验,如唯一约束
}
2025-11-25 01:13:26 +08:00
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.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个子库位
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);
// 按父库位排序(保持物理顺序)
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<WmsActualWarehouse> 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());
upd.setSplitStatus(1);
upd.setSplitType(splitType);
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));
for (WmsActualWarehouse parent : parents) {
Integer splitStatus = Optional.ofNullable(parent.getSplitStatus()).orElse(0);
if (splitStatus != 1) {
// 未拆分状态,无需处理
continue;
}
// 查询父库位下的所有四级子库位(包含已逻辑删除的)
List<WmsActualWarehouse> children = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
.eq(WmsActualWarehouse::getParentId, parent.getActualWarehouseId())
.eq(WmsActualWarehouse::getActualWarehouseType, 4)
.eq(WmsActualWarehouse::getDelFlag, 0));
if (CollUtil.isEmpty(children)) {
// 无子库位,直接还原父库位状态
resetParentLocationStatus(parent);
continue;
}
// 检查子库位是否被占用(仅检查未删除的子库位)
boolean anyOccupied = children.stream()
.filter(c -> c.getDelFlag() == 0) // 只检查启用中的子库位
.anyMatch(c -> !Objects.equals(c.getIsEnabled(), 1));
if (anyOccupied) {
throw new ServiceException("小库位被占用,不能合并:" + parent.getActualWarehouseCode());
}
// 逻辑删除子库位(保留数据,用于后续拆分复用)
for (WmsActualWarehouse child : children) {
WmsActualWarehouse updChild = new WmsActualWarehouse();
updChild.setActualWarehouseId(child.getActualWarehouseId());
updChild.setDelFlag(1); // 逻辑删除
updChild.setIsEnabled(0); // 禁用
baseMapper.updateById(updChild);
}
// 还原父库位状态
resetParentLocationStatus(parent);
}
}
/**
* 重置父库位拆分状态通用方法
*/
private void resetParentLocationStatus(WmsActualWarehouse parent) {
WmsActualWarehouse upd = new WmsActualWarehouse();
upd.setActualWarehouseId(parent.getActualWarehouseId());
upd.setSplitStatus(0); // 还原为未拆分
upd.setSplitType(0); // 清空拆分类型
baseMapper.updateById(upd);
}
}