refactor(wms): 优化退库操作流程

- 移除了不必要的验证逻辑,简化了代码结构
- 使用 stream API 优化了原出库明细的查找和已退库数量的计算
-调整了退库数量验证的逻辑,提高了用户体验
-优化了单位的获取逻辑,增加了默认值
This commit is contained in:
2025-08-12 10:31:19 +08:00
parent 596c5d51ff
commit 408ce31776

View File

@@ -191,170 +191,84 @@ public class WmsStockIoServiceImpl implements IWmsStockIoService {
@Override
@Transactional(rollbackFor = Exception.class)
public boolean scanReturnStockByBo(WmsStockIoBo bo) {
// 退库操作:根据id查询明细根据parent_id获取原出库单明细验证退库数量
// 退库操作:根据明细ID查询明细根据parent_id获取原出库单明细验证退库数量
if (bo.getStockIoId() == null) {
throw new ServiceException("退库ID不能为空");
throw new ServiceException("退库明细ID不能为空");
}
// 1. 根据id查询退库单明细
// 1. 根据明细ID查询退库单明细
WmsStockIoDetail returnDetail = stockIoDetailMapper.selectById(bo.getStockIoId());
if (returnDetail == null) {
throw new ServiceException("退库明细不存在");
}
// 验证退库数量必须大于0
if (returnDetail.getQuantity() == null || returnDetail.getQuantity().compareTo(BigDecimal.ZERO) <= 0) {
throw new ServiceException("退库数量必须大于0");
}
// 验证物品类型和物品ID的有效性
if (returnDetail.getItemType() == null || returnDetail.getItemId() == null) {
throw new ServiceException("物品类型和物品ID不能为空");
}
if (!"product".equals(returnDetail.getItemType()) && !"raw_material".equals(returnDetail.getItemType())) {
throw new ServiceException("物品类型必须是product或raw_material");
}
// 验证库位ID的有效性
if (returnDetail.getWarehouseId() == null) {
throw new ServiceException("库位ID不能为空");
}
// 验证物品是否存在
if ("product".equals(returnDetail.getItemType())) {
WmsProduct product = productMapper.selectById(returnDetail.getItemId());
if (product == null) {
throw new ServiceException("产品不存在");
}
} else if ("raw_material".equals(returnDetail.getItemType())) {
WmsRawMaterial rawMaterial = rawMaterialMapper.selectById(returnDetail.getItemId());
if (rawMaterial == null) {
throw new ServiceException("原材料不存在");
}
}
// 验证库位是否存在
WmsWarehouse warehouse = warehouseMapper.selectById(returnDetail.getWarehouseId());
if (warehouse == null) {
throw new ServiceException("库位不存在");
}
// 验证库位是否启用
if (warehouse.getIsEnabled() == null || warehouse.getIsEnabled() != 1) {
throw new ServiceException("库位未启用,无法进行退库操作");
}
// 2. 获取退库单主表信息
WmsStockIo returnStockIo = baseMapper.selectById(returnDetail.getStockIoId());
if (returnStockIo == null) {
throw new ServiceException("退库单不存在");
if (returnStockIo == null || returnStockIo.getParentId() == null) {
throw new ServiceException("退库单不存在或未关联原出库单");
}
// 验证退库单类型必须是库类型
if (!"in".equals(returnStockIo.getIoType())) {
throw new ServiceException("退库单类型必须是库类型");
}
// 验证退库单状态必须是已提交或已审核状态
if (returnStockIo.getStatus() == null || (returnStockIo.getStatus() != 1 && returnStockIo.getStatus() != 2)) {
throw new ServiceException("退库单必须是已提交或已审核状态才能执行退库操作");
}
// 3. 根据parent_id获取原出库单的所有明细
if (returnStockIo.getParentId() == null) {
throw new ServiceException("退库单未关联原出库单");
// 验证退库单类型必须是退库类型
if (!"withdraw".equals(returnStockIo.getIoType())) {
throw new ServiceException("类型必须是退库类型");
}
// 3. 获取原出库单信息
WmsStockIo originalOutStockIo = baseMapper.selectById(returnStockIo.getParentId());
if (originalOutStockIo == null) {
throw new ServiceException("原出库单不存在");
if (originalOutStockIo == null || !"out".equals(originalOutStockIo.getIoType())) {
throw new ServiceException("原出库单不存在或类型错误");
}
if (!"out".equals(originalOutStockIo.getIoType())) {
throw new ServiceException("原单据不是出库单");
}
// 验证原出库单状态必须是已审核状态
if (originalOutStockIo.getStatus() == null || originalOutStockIo.getStatus() != 2) {
throw new ServiceException("原出库单必须是已审核状态才能进行退库操作");
}
// 4. 获取原出库单的所有明细
// 4. 查找对应的原出库明细
List<WmsStockIoDetail> originalOutDetails = stockIoDetailMapper.selectList(
Wrappers.<WmsStockIoDetail>lambdaQuery()
.eq(WmsStockIoDetail::getStockIoId, returnStockIo.getParentId())
);
if (originalOutDetails == null || originalOutDetails.isEmpty()) {
throw new ServiceException("原出库单明细不存在");
}
// 5. 查找对应的原出库明细根据物品类型、物品ID、库位ID匹配
WmsStockIoDetail originalOutDetail = null;
for (WmsStockIoDetail detail : originalOutDetails) {
if (detail.getItemType().equals(returnDetail.getItemType()) &&
detail.getItemId().equals(returnDetail.getItemId()) &&
detail.getWarehouseId().equals(returnDetail.getWarehouseId())) {
originalOutDetail = detail;
break;
}
}
WmsStockIoDetail originalOutDetail = originalOutDetails.stream()
.filter(detail -> detail.getItemType().equals(returnDetail.getItemType()) &&
detail.getItemId().equals(returnDetail.getItemId()) &&
detail.getWarehouseId().equals(returnDetail.getWarehouseId()))
.findFirst()
.orElse(null);
if (originalOutDetail == null) {
throw new ServiceException("未找到对应的原出库明细");
}
// 6. 查询该物品已退库的总数量
BigDecimal totalReturnedQty = BigDecimal.ZERO;
List<WmsStockIo> returnStockIos = baseMapper.selectList(
// 5. 验证退库数量不能超过原出库数量
BigDecimal totalReturnedQty = baseMapper.selectList(
Wrappers.<WmsStockIo>lambdaQuery()
.eq(WmsStockIo::getParentId, returnStockIo.getParentId())
.eq(WmsStockIo::getIoType, "in") // 退库单类型为入库
);
.eq(WmsStockIo::getIoType, "withdraw")
.ne(WmsStockIo::getStockIoId, returnStockIo.getStockIoId())
).stream()
.flatMap(returnStockIoItem -> stockIoDetailMapper.selectList(
Wrappers.<WmsStockIoDetail>lambdaQuery()
.eq(WmsStockIoDetail::getStockIoId, returnStockIoItem.getStockIoId())
.eq(WmsStockIoDetail::getItemType, returnDetail.getItemType())
.eq(WmsStockIoDetail::getItemId, returnDetail.getItemId())
.eq(WmsStockIoDetail::getWarehouseId, returnDetail.getWarehouseId())
).stream())
.map(WmsStockIoDetail::getQuantity)
.reduce(BigDecimal.ZERO, BigDecimal::add);
for (WmsStockIo returnStockIoItem : returnStockIos) {
// 排除当前正在处理的退库单
if (returnStockIoItem.getStockIoId().equals(returnStockIo.getStockIoId())) {
continue;
}
List<WmsStockIoDetail> returnDetails = stockIoDetailMapper.selectList(
Wrappers.<WmsStockIoDetail>lambdaQuery()
.eq(WmsStockIoDetail::getStockIoId, returnStockIoItem.getStockIoId())
.eq(WmsStockIoDetail::getItemType, returnDetail.getItemType())
.eq(WmsStockIoDetail::getItemId, returnDetail.getItemId())
.eq(WmsStockIoDetail::getWarehouseId, returnDetail.getWarehouseId())
);
for (WmsStockIoDetail detail : returnDetails) {
totalReturnedQty = totalReturnedQty.add(detail.getQuantity());
}
}
// 7. 验证退库数量不能超过原出库数量
BigDecimal remainingQty = originalOutDetail.getQuantity().subtract(totalReturnedQty);
if (returnDetail.getQuantity().compareTo(remainingQty) > 0) {
throw new ServiceException("退库数量超过原出库数量,原出库数量:" + originalOutDetail.getQuantity() +
",已退库数量:" + totalReturnedQty + ",剩余可退数量:" + remainingQty +
",本次退库数量:" + returnDetail.getQuantity());
throw new ServiceException("退库数量超过原出库数量,剩余可退数量:" + remainingQty);
}
// 8. 执行退库操作(增加库存)
// 6. 执行退库操作(增加库存)
String unit = returnDetail.getUnit();
// 如果unit为空自动查item表补全
if (unit == null || unit.trim().isEmpty()) {
if ("product".equals(returnDetail.getItemType())) {
WmsProduct p = productMapper.selectById(returnDetail.getItemId());
unit = p != null ? p.getUnit() : null;
unit = p != null ? p.getUnit() : "";
} else if ("raw_material".equals(returnDetail.getItemType())) {
WmsRawMaterial r = rawMaterialMapper.selectById(returnDetail.getItemId());
unit = r != null ? r.getUnit() : null;
unit = r != null ? r.getUnit() : "";
}
}
if (unit == null || unit.trim().isEmpty()) {
throw new ServiceException("未能获取到单位");
}
// 执行入库操作(退库就是入库)
changeStock(returnDetail.getWarehouseId(), returnDetail.getItemType(),