feat(wms): 添加钢卷库位分配校验功能

- 实现了实际库位占用状态校验逻辑
- 添加了三级库位拆分状态检查机制
- 实现了四级库位父子层级关系验证
- 在钢卷新增操作中集成库位校验
- 在钢卷修改操作中集成库位校验
- 在钢卷分卷操作中对子卷库位进行校验
- 在钢卷合卷操作中对目标库位进行校验
- 支持忽略同库位重复占用校验的特殊场景
This commit is contained in:
2026-01-13 14:16:02 +08:00
parent 102eb8bea7
commit 2ca1e3e705

View File

@@ -375,6 +375,11 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
}
}
// 仅查询废品:质量状态为 D+、D、D-
if (Boolean.TRUE.equals(bo.getOnlyScrap())) {
qw.in("mc.quality_status", java.util.Arrays.asList("D+", "D", "D-"));
}
// 组合 item_id 条件:改为使用 EXISTS 子查询,替代预查询 + IN
boolean hasSelectType = StringUtils.isNotBlank(bo.getSelectType());
boolean hasAnyItemFilter = StringUtils.isNotBlank(bo.getItemMaterial())
@@ -624,6 +629,48 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
// 一级库位或其他类型返回自身ID
return Collections.singletonList(actualWarehouseId);
}
/**
* 校验实际库位是否可用于分配给钢卷:
* - 若库位被占用isEnabled=0则禁止除非本次操作是继续使用同一已占用库位的场景可通过 ignoreOccupiedId 放行占用校验)。
* - 若为三级库位且已拆分splitStatus=1禁止直接在三级库位上新增/修改。
* - 若为四级库位且其父级三级库位未拆分splitStatus!=1禁止使用该四级库位。
*/
private void validateActualWarehouseForAssign(Long actualWarehouseId, Long ignoreOccupiedId) {
if (actualWarehouseId == null) {
return;
}
WmsActualWarehouseVo aw = actualWarehouseService.queryById(actualWarehouseId);
if (aw == null) {
throw new RuntimeException("实际库区不存在");
}
// 占用校验isEnabled=0 视为已被占用)
if (aw.getIsEnabled() != null && aw.getIsEnabled() == 0
&& (ignoreOccupiedId == null || !actualWarehouseId.equals(ignoreOccupiedId))) {
throw new RuntimeException("实际库区已被占用,请选择其他库区");
}
Long type = aw.getActualWarehouseType();
Integer splitStatus = aw.getSplitStatus();
// 三级库位且已拆分,禁止直接在三级层级使用
if (type != null && type == 3L && splitStatus != null && splitStatus == 1) {
throw new RuntimeException("该库位已被拆分,刷新后重试");
}
// 四级库位:父级必须是已拆分的三级库位
if (type != null && type == 4L) {
Long parentId = aw.getParentId();
if (parentId != null) {
WmsActualWarehouseVo parent = actualWarehouseService.queryById(parentId);
if (parent != null) {
Integer pSplit = parent.getSplitStatus();
Long pType = parent.getActualWarehouseType();
if (pType != null && pType == 3L && (pSplit == null || pSplit != 1)) {
throw new RuntimeException("该库位已被合并,刷新后重试");
}
}
}
}
}
/**
* 查询钢卷物料表列表
*/
@@ -698,7 +745,12 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
}else {
add.setDataType(1); // 新增的钢卷默认为当前数据
}
// 实际库位校验:占用与拆分/层级规则
if (bo.getActualWarehouseId() != null) {
validateActualWarehouseForAssign(bo.getActualWarehouseId(), null);
}
validEntityBeforeSave(add);
// 在新增钢卷数据之前需要先看库区id是否被占用如果被占用则不能新增抛异常为实际库区已被占用 不能再当前库区修改或者新增
int rows = baseMapper.insert(add);
if (rows <= 0) {
throw new RuntimeException("新增钢卷失败");
@@ -842,6 +894,14 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
throw new RuntimeException("钢卷不存在");
}
// 若修改实际库位,先进行校验
if (bo.getActualWarehouseId() != null) {
// 若与原库位不同,常规占用校验;若相同,仅校验拆分/层级
Long ignoreOccupiedId = Objects.equals(bo.getActualWarehouseId(), oldCoil.getActualWarehouseId())
? bo.getActualWarehouseId() : null;
validateActualWarehouseForAssign(bo.getActualWarehouseId(), ignoreOccupiedId);
}
// 直接更新钢卷属性
WmsMaterialCoil updateCoil = BeanUtil.toBean(bo, WmsMaterialCoil.class);
validEntityBeforeSave(updateCoil);
@@ -889,6 +949,13 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
throw new RuntimeException("原钢卷不存在");
}
// 若修改实际库位,先进行校验
if (bo.getActualWarehouseId() != null) {
Long ignoreOccupiedId = Objects.equals(bo.getActualWarehouseId(), oldCoil.getActualWarehouseId())
? bo.getActualWarehouseId() : null;
validateActualWarehouseForAssign(bo.getActualWarehouseId(), ignoreOccupiedId);
}
// 1. 将原钢卷标记为历史数据dataType = 0
LambdaUpdateWrapper<WmsMaterialCoil> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(WmsMaterialCoil::getCoilId, oldCoil.getCoilId())
@@ -1102,6 +1169,12 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
// 3. 为每个分卷后的子钢卷生成独立的二维码并插入数据库
for (WmsMaterialCoilBo newCoilBo : bo.getNewCoils()) {
// 校验每个子卷的实际库位
if (newCoilBo.getActualWarehouseId() != null) {
Long ignoreOccupiedId = (oldCoil != null && Objects.equals(newCoilBo.getActualWarehouseId(), oldCoil.getActualWarehouseId()))
? newCoilBo.getActualWarehouseId() : null;
validateActualWarehouseForAssign(newCoilBo.getActualWarehouseId(), ignoreOccupiedId);
}
WmsMaterialCoil newCoil = BeanUtil.toBean(newCoilBo, WmsMaterialCoil.class);
newCoil.setCoilId(null);
newCoil.setDataType(1);
@@ -1180,6 +1253,10 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
Long mergedQrcodeId = generateQrcodeForMerge(bo, bo.getNewCoils());
// 3. 插入合卷后的新钢卷
// 合卷结果若指定了实际库位,先进行校验
if (bo.getActualWarehouseId() != null) {
validateActualWarehouseForAssign(bo.getActualWarehouseId(), null);
}
WmsMaterialCoil newCoil = BeanUtil.toBean(bo, WmsMaterialCoil.class);
newCoil.setCoilId(null);
newCoil.setDataType(1);