2025-11-03 13:47:38 +08:00
|
|
|
|
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;
|
2025-11-03 13:47:38 +08:00
|
|
|
|
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;
|
2025-11-03 13:47:38 +08:00
|
|
|
|
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;
|
2025-11-03 13:47:38 +08:00
|
|
|
|
import com.klp.domain.bo.WmsActualWarehouseBo;
|
2025-11-25 01:13:26 +08:00
|
|
|
|
import com.klp.domain.bo.WmsActualWarehouseHierarchyBo;
|
2025-12-05 09:31:08 +08:00
|
|
|
|
import com.klp.domain.bo.WmsActualWarehouseBatchGenerateBo;
|
2025-12-19 13:53:36 +08:00
|
|
|
|
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;
|
2025-11-03 13:47:38 +08:00
|
|
|
|
import com.klp.domain.vo.WmsActualWarehouseVo;
|
|
|
|
|
|
import com.klp.domain.WmsActualWarehouse;
|
|
|
|
|
|
import com.klp.mapper.WmsActualWarehouseMapper;
|
|
|
|
|
|
import com.klp.service.IWmsActualWarehouseService;
|
2025-12-06 10:28:24 +08:00
|
|
|
|
import com.klp.domain.WmsMaterialCoil;
|
|
|
|
|
|
import com.klp.mapper.WmsMaterialCoilMapper;
|
2025-11-03 13:47:38 +08:00
|
|
|
|
|
2025-11-25 01:13:26 +08:00
|
|
|
|
import java.util.*;
|
|
|
|
|
|
import java.util.stream.Collectors;
|
2025-11-03 13:47:38 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 实际库区/库位自关联Service业务层处理
|
|
|
|
|
|
*
|
|
|
|
|
|
* @author klp
|
2025-11-24 11:32:37 +08:00
|
|
|
|
* @date 2025-11-24
|
2025-11-03 13:47:38 +08:00
|
|
|
|
*/
|
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
|
|
@Service
|
|
|
|
|
|
public class WmsActualWarehouseServiceImpl implements IWmsActualWarehouseService {
|
|
|
|
|
|
|
|
|
|
|
|
private final WmsActualWarehouseMapper baseMapper;
|
2025-12-06 10:28:24 +08:00
|
|
|
|
private final WmsMaterialCoilMapper wmsMaterialCoilMapper;
|
2025-11-03 13:47:38 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 查询实际库区/库位自关联
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Override
|
2025-12-20 09:55:56 +08:00
|
|
|
|
public WmsActualWarehouseVo queryById(Long actualWarehouseId) {
|
2025-11-03 13:47:38 +08:00
|
|
|
|
return baseMapper.selectVoById(actualWarehouseId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-05 09:31:08 +08:00
|
|
|
|
@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();
|
2025-12-08 11:15:22 +08:00
|
|
|
|
if (layers == null) {
|
|
|
|
|
|
layers = 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (rows == null || cols == null || rows < 1 || cols < 1) {
|
|
|
|
|
|
throw new ServiceException("行/列必须为正整数");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (layers < 1) {
|
|
|
|
|
|
throw new ServiceException("层必须为正整数");
|
2025-12-05 09:31:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (StringUtils.isBlank(prefix)) {
|
|
|
|
|
|
throw new ServiceException("前缀不能为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
List<String> codes = new ArrayList<>(rows * cols * layers);
|
2025-12-08 11:15:22 +08:00
|
|
|
|
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++) {
|
2025-12-08 11:24:54 +08:00
|
|
|
|
String rStr = r < 10 ? ("0" + r) : String.valueOf(r);
|
|
|
|
|
|
String code = prefix + c + '-' + rStr + '-' + l;
|
2025-12-05 09:31:08 +08:00
|
|
|
|
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);
|
2025-12-05 11:35:41 +08:00
|
|
|
|
e.setActualWarehouseType(3L);
|
2025-12-05 09:31:08 +08:00
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 13:47:38 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 查询实际库区/库位自关联列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public List<WmsActualWarehouseVo> queryList(WmsActualWarehouseBo bo) {
|
|
|
|
|
|
LambdaQueryWrapper<WmsActualWarehouse> lqw = buildQueryWrapper(bo);
|
2025-12-06 10:28:24 +08:00
|
|
|
|
List<WmsActualWarehouseVo> list = baseMapper.selectVoList(lqw);
|
|
|
|
|
|
|
|
|
|
|
|
if (CollUtil.isEmpty(list)) {
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-19 13:53:36 +08:00
|
|
|
|
// 如果当前查询的是某二级父节点下的三级库位,需要将被拆分的大库位替换为其两个子库位
|
|
|
|
|
|
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)
|
2025-12-20 09:55:56 +08:00
|
|
|
|
.orderByAsc(WmsActualWarehouse::getActualWarehouseCode, WmsActualWarehouse::getActualWarehouseId)
|
2025-12-19 13:53:36 +08:00
|
|
|
|
);
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-06 10:28:24 +08:00
|
|
|
|
// 仅对被占用的位置(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-03 13:47:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
2025-11-25 10:41:04 +08:00
|
|
|
|
@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);
|
2025-12-19 15:28:30 +08:00
|
|
|
|
// 四级节点也排除
|
|
|
|
|
|
wrapper.ne(WmsActualWarehouse::getActualWarehouseType, 4);
|
2025-11-25 10:41:04 +08:00
|
|
|
|
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
|
|
|
|
|
2025-11-03 13:47:38 +08:00
|
|
|
|
private LambdaQueryWrapper<WmsActualWarehouse> buildQueryWrapper(WmsActualWarehouseBo bo) {
|
|
|
|
|
|
Map<String, Object> params = bo.getParams();
|
|
|
|
|
|
LambdaQueryWrapper<WmsActualWarehouse> lqw = Wrappers.lambdaQuery();
|
2025-11-24 11:41:12 +08:00
|
|
|
|
lqw.eq(bo.getParentId() != null, WmsActualWarehouse::getParentId, bo.getParentId());
|
2025-11-03 13:47:38 +08:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 13:47:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 保存前的数据校验
|
|
|
|
|
|
*/
|
2025-12-20 09:55:56 +08:00
|
|
|
|
private void validEntityBeforeSave(WmsActualWarehouse entity) {
|
2025-11-03 13:47:38 +08:00
|
|
|
|
//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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 13:47:38 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 批量删除实际库区/库位自关联
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
2025-12-20 09:55:56 +08:00
|
|
|
|
if (isValid) {
|
2025-11-03 13:47:38 +08:00
|
|
|
|
//TODO 做一些业务上的校验,判断是否需要校验
|
|
|
|
|
|
}
|
|
|
|
|
|
return baseMapper.deleteBatchIds(ids) > 0;
|
|
|
|
|
|
}
|
2025-11-25 10:41:04 +08:00
|
|
|
|
|
2025-12-19 13:53:36 +08:00
|
|
|
|
@Override
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
|
public void splitLocations(WmsActualWarehouseSplitBo bo) {
|
2025-12-20 09:55:56 +08:00
|
|
|
|
if (bo == null) {
|
2025-12-19 13:53:36 +08:00
|
|
|
|
throw new ServiceException("参数不能为空");
|
|
|
|
|
|
}
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
|
|
|
|
|
// 参数验证
|
|
|
|
|
|
String columnFlag = bo.getColumnFlag();
|
|
|
|
|
|
if (StringUtils.isBlank(columnFlag)) {
|
|
|
|
|
|
throw new ServiceException("列标识不能为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-19 13:53:36 +08:00
|
|
|
|
int splitType = Optional.ofNullable(bo.getSplitType()).orElse(0);
|
2025-12-20 16:31:24 +08:00
|
|
|
|
List<Long> Ids = Optional.ofNullable(bo.getSplitIds()).orElse(new ArrayList<>());
|
|
|
|
|
|
|
|
|
|
|
|
// 合并所有待拆分的ID
|
|
|
|
|
|
Set<Long> splitIds = new HashSet<>();
|
|
|
|
|
|
splitIds.addAll(Ids);
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
|
|
|
|
|
if (splitIds.isEmpty()) {
|
|
|
|
|
|
throw new ServiceException("待拆分库位ID列表不能为空");
|
2025-12-19 13:53:36 +08:00
|
|
|
|
}
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 根据列标识查询该列的所有库位(第一层和第二层)
|
2025-12-20 09:55:56 +08:00
|
|
|
|
List<WmsActualWarehouse> columnLocations = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
|
2025-12-26 10:54:43 +08:00
|
|
|
|
.likeRight(WmsActualWarehouse::getActualWarehouseCode, columnFlag + "-")
|
2025-12-20 09:55:56 +08:00
|
|
|
|
.eq(WmsActualWarehouse::getDelFlag, 0)
|
2025-12-20 16:31:24 +08:00
|
|
|
|
.eq(WmsActualWarehouse::getActualWarehouseType, 3) // 只查询三级库位
|
2025-12-20 09:55:56 +08:00
|
|
|
|
.orderByAsc(WmsActualWarehouse::getActualWarehouseCode));
|
|
|
|
|
|
|
|
|
|
|
|
if (CollUtil.isEmpty(columnLocations)) {
|
|
|
|
|
|
throw new ServiceException("未找到列标识为 " + columnFlag + " 的库位");
|
2025-12-19 13:53:36 +08:00
|
|
|
|
}
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
2025-12-22 13:50:31 +08:00
|
|
|
|
// 检查整个列中是否有任何库位被占用
|
2025-12-22 09:36:31 +08:00
|
|
|
|
List<String> occupiedCodes = new ArrayList<>();
|
2025-12-22 13:50:31 +08:00
|
|
|
|
for (WmsActualWarehouse location : columnLocations) {
|
2025-12-22 09:36:31 +08:00
|
|
|
|
// 锁定状态=0 → 被占用
|
2025-12-22 13:50:31 +08:00
|
|
|
|
boolean isOccupied = location.getIsEnabled() != null && location.getIsEnabled() == 0;
|
2025-12-22 09:36:31 +08:00
|
|
|
|
if (isOccupied) {
|
2025-12-22 13:50:31 +08:00
|
|
|
|
occupiedCodes.add(location.getActualWarehouseCode());
|
2025-12-22 09:36:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-22 13:50:31 +08:00
|
|
|
|
// 如果有任何库位被占用,抛出异常提示
|
2025-12-22 09:36:31 +08:00
|
|
|
|
if (!occupiedCodes.isEmpty()) {
|
2025-12-22 13:50:31 +08:00
|
|
|
|
throw new ServiceException("以下库位被占用,无法拆分:" + String.join(",", occupiedCodes));
|
2025-12-22 09:36:31 +08:00
|
|
|
|
}
|
2025-12-22 13:50:31 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
// 批量查询所有子库位(一次性查询,避免循环查询)
|
|
|
|
|
|
List<Long> parentIds = columnLocations.stream()
|
|
|
|
|
|
.map(WmsActualWarehouse::getActualWarehouseId)
|
|
|
|
|
|
.collect(Collectors.toList());
|
2025-12-22 09:36:31 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
List<WmsActualWarehouse> allChildren = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
|
|
|
|
|
|
.in(WmsActualWarehouse::getParentId, parentIds)
|
|
|
|
|
|
.eq(WmsActualWarehouse::getActualWarehouseType, 4)); // 四级子库位
|
2025-12-22 09:36:31 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
boolean hasExistingChildren = CollUtil.isNotEmpty(allChildren);
|
2025-12-20 16:31:24 +08:00
|
|
|
|
|
|
|
|
|
|
if (hasExistingChildren) {
|
|
|
|
|
|
// 如果已经有子库位,执行复活逻辑
|
2025-12-20 16:44:19 +08:00
|
|
|
|
reviveExistingSubLocations(columnLocations, splitIds, splitType, allChildren);
|
2025-12-20 16:31:24 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
// 如果没有子库位,执行创建逻辑
|
|
|
|
|
|
createNewSubLocationsWithOriginalLogic(columnLocations, splitIds, splitType, columnFlag);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
// 批量更新该列所有被拆分库位的状态
|
|
|
|
|
|
List<WmsActualWarehouse> toUpdate = new ArrayList<>();
|
2025-12-20 16:31:24 +08:00
|
|
|
|
for (WmsActualWarehouse location : columnLocations) {
|
|
|
|
|
|
WmsActualWarehouse upd = new WmsActualWarehouse();
|
|
|
|
|
|
upd.setActualWarehouseId(location.getActualWarehouseId());
|
|
|
|
|
|
upd.setSplitStatus(1);
|
|
|
|
|
|
upd.setSplitType(splitType);
|
2025-12-20 16:44:19 +08:00
|
|
|
|
toUpdate.add(upd);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!toUpdate.isEmpty()) {
|
|
|
|
|
|
baseMapper.updateBatchById(toUpdate);
|
2025-12-20 16:31:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2025-12-20 16:44:19 +08:00
|
|
|
|
* 复活已存在的子库位(优化版:批量操作)
|
2025-12-20 16:31:24 +08:00
|
|
|
|
*/
|
2025-12-20 16:44:19 +08:00
|
|
|
|
private void reviveExistingSubLocations(List<WmsActualWarehouse> columnLocations, Set<Long> splitIds, Integer splitType, List<WmsActualWarehouse> allChildren) {
|
|
|
|
|
|
// 按父ID分组子库位
|
|
|
|
|
|
Map<Long, List<WmsActualWarehouse>> childrenByParent = allChildren.stream()
|
|
|
|
|
|
.sorted(Comparator.comparing(WmsActualWarehouse::getActualWarehouseId))
|
|
|
|
|
|
.collect(Collectors.groupingBy(WmsActualWarehouse::getParentId, LinkedHashMap::new, Collectors.toList()));
|
|
|
|
|
|
|
|
|
|
|
|
List<WmsActualWarehouse> toUpdate = new ArrayList<>();
|
2025-12-22 09:36:31 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
for (WmsActualWarehouse location : columnLocations) {
|
|
|
|
|
|
boolean isSplitLocation = splitIds.contains(location.getActualWarehouseId());
|
2025-12-20 16:44:19 +08:00
|
|
|
|
List<WmsActualWarehouse> children = childrenByParent.get(location.getActualWarehouseId());
|
2025-12-22 09:36:31 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
if (CollUtil.isEmpty(children)) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-12-20 16:31:24 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
// 根据是否为拆分库位决定需要复活的子库位数量
|
|
|
|
|
|
int requiredCount = isSplitLocation ? 2 : 1;
|
|
|
|
|
|
|
|
|
|
|
|
// 复活前N个子库位
|
|
|
|
|
|
for (int i = 0; i < Math.min(requiredCount, children.size()); i++) {
|
|
|
|
|
|
WmsActualWarehouse child = children.get(i);
|
|
|
|
|
|
if (child.getDelFlag() == 1) { // 只处理已删除的子库位
|
|
|
|
|
|
WmsActualWarehouse childUpdate = new WmsActualWarehouse();
|
|
|
|
|
|
childUpdate.setActualWarehouseId(child.getActualWarehouseId());
|
|
|
|
|
|
childUpdate.setDelFlag(0);
|
|
|
|
|
|
childUpdate.setSplitStatus(1);
|
|
|
|
|
|
childUpdate.setSplitType(splitType);
|
|
|
|
|
|
toUpdate.add(childUpdate);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 16:31:24 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
// 如果子库位数量超过需要的数量,隐藏多余的
|
|
|
|
|
|
if (children.size() > requiredCount) {
|
|
|
|
|
|
for (int i = requiredCount; i < children.size(); i++) {
|
|
|
|
|
|
WmsActualWarehouse child = children.get(i);
|
|
|
|
|
|
if (child.getDelFlag() == 0) { // 只处理未删除的子库位
|
2025-12-20 16:31:24 +08:00
|
|
|
|
WmsActualWarehouse childUpdate = new WmsActualWarehouse();
|
|
|
|
|
|
childUpdate.setActualWarehouseId(child.getActualWarehouseId());
|
2025-12-20 16:44:19 +08:00
|
|
|
|
childUpdate.setDelFlag(1);
|
|
|
|
|
|
toUpdate.add(childUpdate);
|
2025-12-20 16:31:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-22 09:36:31 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
// 批量更新
|
|
|
|
|
|
if (!toUpdate.isEmpty()) {
|
|
|
|
|
|
baseMapper.updateBatchById(toUpdate);
|
|
|
|
|
|
}
|
2025-12-20 16:31:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 使用逻辑创建新的子库位
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void createNewSubLocationsWithOriginalLogic(List<WmsActualWarehouse> columnLocations, Set<Long> splitIds, Integer splitType, String columnFlag) {
|
2025-12-20 09:55:56 +08:00
|
|
|
|
// 分离需要拆分的库位和剩余库位
|
|
|
|
|
|
List<WmsActualWarehouse> splitLocations = new ArrayList<>();
|
|
|
|
|
|
List<WmsActualWarehouse> remainingLocations = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
|
|
for (WmsActualWarehouse location : columnLocations) {
|
|
|
|
|
|
if (splitIds.contains(location.getActualWarehouseId())) {
|
|
|
|
|
|
splitLocations.add(location);
|
2025-12-19 13:53:36 +08:00
|
|
|
|
} else {
|
2025-12-20 09:55:56 +08:00
|
|
|
|
remainingLocations.add(location);
|
2025-12-19 13:53:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 第一步:先创建所有子库位(不设置编码)
|
2025-12-20 09:55:56 +08:00
|
|
|
|
List<WmsActualWarehouse> toInsert = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 处理需要拆分的库位(每个拆分为2个子库位)
|
|
|
|
|
|
for (WmsActualWarehouse location : splitLocations) {
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 生成第一个子库位
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
// 生成第二个子库位
|
|
|
|
|
|
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个子库位,保持原层级)
|
2025-12-20 13:52:29 +08:00
|
|
|
|
for (WmsActualWarehouse remainingLocation : remainingLocations) {
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 生成剩余库位的子库位
|
|
|
|
|
|
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);
|
2025-12-20 09:55:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 验证总数
|
2025-12-20 16:31:24 +08:00
|
|
|
|
int expectedSplitSubLocations = splitLocations.size() * 2;
|
|
|
|
|
|
int expectedRemainingSubLocations = remainingLocations.size() * 1;
|
|
|
|
|
|
int expectedTotalSubLocations = expectedSplitSubLocations + expectedRemainingSubLocations;
|
|
|
|
|
|
int actualTotalSubLocations = toInsert.size();
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
if (actualTotalSubLocations != expectedTotalSubLocations) {
|
2025-12-20 09:55:56 +08:00
|
|
|
|
throw new ServiceException(String.format(
|
2025-12-20 16:31:24 +08:00
|
|
|
|
"子库位生成数量不匹配,期望%d个(拆分库位:%d个→%d个,剩余库位:%d个→%d个),实际生成%d个",
|
|
|
|
|
|
expectedTotalSubLocations,
|
|
|
|
|
|
splitLocations.size(), expectedSplitSubLocations,
|
|
|
|
|
|
remainingLocations.size(), expectedRemainingSubLocations,
|
|
|
|
|
|
actualTotalSubLocations
|
|
|
|
|
|
));
|
2025-12-20 09:55:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 4. 批量插入子库位(先插入获取ID)
|
2025-12-19 13:53:36 +08:00
|
|
|
|
if (!toInsert.isEmpty()) {
|
2025-12-20 16:31:24 +08:00
|
|
|
|
boolean ok = baseMapper.insertBatch(toInsert);
|
|
|
|
|
|
if (!ok) {
|
2025-12-20 09:55:56 +08:00
|
|
|
|
throw new ServiceException("新增子库位失败");
|
2025-12-19 13:53:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 第二步:重新生成编码
|
|
|
|
|
|
String prefix = columnFlag;
|
|
|
|
|
|
List<WmsActualWarehouse> toUpdate = new ArrayList<>();
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 1. 先把所有子库位按父库位排序
|
|
|
|
|
|
List<WmsActualWarehouse> 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);
|
|
|
|
|
|
});
|
2025-12-20 14:50:21 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 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...)
|
2025-12-20 09:55:56 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 生成编码:前缀-两位序号-层级(如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);
|
2025-12-20 14:50:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 3. 批量更新编码
|
|
|
|
|
|
if (!toUpdate.isEmpty()) {
|
2025-12-20 16:44:19 +08:00
|
|
|
|
baseMapper.updateBatchById(toUpdate);
|
2025-12-19 13:53:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
|
public void mergeLocations(WmsActualWarehouseSplitBo bo) {
|
2025-12-20 16:31:24 +08:00
|
|
|
|
if (bo == null) {
|
2025-12-19 13:53:36 +08:00
|
|
|
|
throw new ServiceException("参数不能为空");
|
|
|
|
|
|
}
|
2025-12-20 13:52:29 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 获取列标识
|
|
|
|
|
|
String columnFlag = bo.getColumnFlag();
|
|
|
|
|
|
if (StringUtils.isBlank(columnFlag)) {
|
|
|
|
|
|
throw new ServiceException("列标识不能为空");
|
2025-12-20 14:50:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 根据列标识查询该列的所有三级库位
|
|
|
|
|
|
List<WmsActualWarehouse> columnLocations = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
|
|
|
|
|
|
.like(WmsActualWarehouse::getActualWarehouseCode, columnFlag)
|
|
|
|
|
|
.eq(WmsActualWarehouse::getDelFlag, 0)
|
|
|
|
|
|
.eq(WmsActualWarehouse::getActualWarehouseType, 3) // 只查询三级库位
|
|
|
|
|
|
.orderByAsc(WmsActualWarehouse::getActualWarehouseCode));
|
2025-12-20 14:50:21 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
if (CollUtil.isEmpty(columnLocations)) {
|
|
|
|
|
|
throw new ServiceException("未找到列标识为 " + columnFlag + " 的库位");
|
2025-12-20 14:50:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
// 过滤出需要合并的库位(splitStatus=1)
|
|
|
|
|
|
List<WmsActualWarehouse> locationsToMerge = columnLocations.stream()
|
|
|
|
|
|
.filter(loc -> Optional.ofNullable(loc.getSplitStatus()).orElse(0) == 1)
|
|
|
|
|
|
.collect(Collectors.toList());
|
2025-12-20 13:52:29 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
if (CollUtil.isEmpty(locationsToMerge)) {
|
|
|
|
|
|
return; // 没有需要合并的库位
|
|
|
|
|
|
}
|
2025-12-20 16:31:24 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
// 批量查询所有子库位
|
2025-12-22 13:50:31 +08:00
|
|
|
|
List<Long> parentIds = columnLocations.stream()
|
2025-12-20 16:44:19 +08:00
|
|
|
|
.map(WmsActualWarehouse::getActualWarehouseId)
|
|
|
|
|
|
.collect(Collectors.toList());
|
2025-12-22 09:36:31 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
List<WmsActualWarehouse> allChildren = baseMapper.selectList(Wrappers.<WmsActualWarehouse>lambdaQuery()
|
|
|
|
|
|
.in(WmsActualWarehouse::getParentId, parentIds)
|
|
|
|
|
|
.eq(WmsActualWarehouse::getActualWarehouseType, 4)); // 四级子库位
|
|
|
|
|
|
|
2025-12-22 13:50:31 +08:00
|
|
|
|
// 检查整列中是否有任何子库位被占用
|
|
|
|
|
|
if (CollUtil.isNotEmpty(allChildren)) {
|
|
|
|
|
|
boolean anyOccupied = allChildren.stream()
|
|
|
|
|
|
.filter(c -> c.getDelFlag() == 0)
|
|
|
|
|
|
.anyMatch(c -> !Objects.equals(c.getIsEnabled(), 1));
|
|
|
|
|
|
if (anyOccupied) {
|
|
|
|
|
|
throw new ServiceException("该列存在被占用的子库位,不能合并");
|
2025-12-20 16:44:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-20 16:31:24 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
// 批量更新子库位和父库位
|
|
|
|
|
|
List<WmsActualWarehouse> childrenToUpdate = new ArrayList<>();
|
|
|
|
|
|
List<WmsActualWarehouse> parentsToUpdate = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
|
|
for (WmsActualWarehouse location : locationsToMerge) {
|
2025-12-22 13:50:31 +08:00
|
|
|
|
List<WmsActualWarehouse> children = allChildren.stream()
|
|
|
|
|
|
.filter(c -> Objects.equals(c.getParentId(), location.getActualWarehouseId()))
|
|
|
|
|
|
.collect(Collectors.toList());
|
2025-12-22 09:36:31 +08:00
|
|
|
|
|
2025-12-20 16:44:19 +08:00
|
|
|
|
// 隐藏所有子库位
|
|
|
|
|
|
if (CollUtil.isNotEmpty(children)) {
|
|
|
|
|
|
for (WmsActualWarehouse child : children) {
|
|
|
|
|
|
if (child.getDelFlag() == 0) {
|
2025-12-20 16:31:24 +08:00
|
|
|
|
WmsActualWarehouse childUpdate = new WmsActualWarehouse();
|
|
|
|
|
|
childUpdate.setActualWarehouseId(child.getActualWarehouseId());
|
2025-12-22 13:50:31 +08:00
|
|
|
|
childUpdate.setDelFlag(1);
|
2025-12-20 16:44:19 +08:00
|
|
|
|
childrenToUpdate.add(childUpdate);
|
2025-12-20 16:31:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-19 13:53:36 +08:00
|
|
|
|
}
|
2025-12-20 13:52:29 +08:00
|
|
|
|
|
2025-12-20 16:31:24 +08:00
|
|
|
|
// 更新父库位状态为未拆分
|
2025-12-20 14:50:21 +08:00
|
|
|
|
WmsActualWarehouse parentUpdate = new WmsActualWarehouse();
|
2025-12-20 16:31:24 +08:00
|
|
|
|
parentUpdate.setActualWarehouseId(location.getActualWarehouseId());
|
2025-12-20 14:50:21 +08:00
|
|
|
|
parentUpdate.setSplitStatus(0);
|
|
|
|
|
|
parentUpdate.setSplitType(0);
|
2025-12-20 16:44:19 +08:00
|
|
|
|
parentsToUpdate.add(parentUpdate);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 批量更新
|
|
|
|
|
|
if (!childrenToUpdate.isEmpty()) {
|
|
|
|
|
|
baseMapper.updateBatchById(childrenToUpdate);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!parentsToUpdate.isEmpty()) {
|
|
|
|
|
|
baseMapper.updateBatchById(parentsToUpdate);
|
2025-12-19 13:53:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-25 10:41:04 +08:00
|
|
|
|
|
2025-11-03 13:47:38 +08:00
|
|
|
|
}
|