feat(wms): 支持库存操作按批次号

- 新增按批次号进行库存增减的功能
- 修改入库、出库、移库等操作,支持指定批次号
- 优化库存查询逻辑,优先按批次号匹配
- 修复测试接口路径配置
This commit is contained in:
2025-09-12 14:26:51 +08:00
parent 3842bb9a84
commit fdec7e1d47
2 changed files with 64 additions and 24 deletions

View File

@@ -158,6 +158,7 @@ security:
# 测试接口 # 测试接口
- /test/** - /test/**
- /klp/generateRecord - /klp/generateRecord
- /klp/generateRecord/**
# MyBatisPlus配置 # MyBatisPlus配置

View File

@@ -163,7 +163,7 @@ public class WmsStockIoServiceImpl implements IWmsStockIoService {
throw new RuntimeException("未能获取到单位"); throw new RuntimeException("未能获取到单位");
} }
// 入库操作 // 入库操作
changeStock(bo.getWarehouseId(), bo.getItemType(), bo.getItemId(), bo.getQuantity(), true, unit); changeStock(bo.getWarehouseId(), bo.getItemType(), bo.getItemId(), bo.getBatchNo(), bo.getQuantity(), true, unit);
return true; return true;
} }
@Override @Override
@@ -184,7 +184,7 @@ public class WmsStockIoServiceImpl implements IWmsStockIoService {
throw new RuntimeException("未能获取到单位"); throw new RuntimeException("未能获取到单位");
} }
// 出库操作 // 出库操作
changeStock(bo.getWarehouseId(), bo.getItemType(), bo.getItemId(), bo.getQuantity(), false, unit); changeStock(bo.getWarehouseId(), bo.getItemType(), bo.getItemId(), bo.getBatchNo(), bo.getQuantity(), false, unit);
return true; return true;
} }
@@ -272,7 +272,7 @@ public class WmsStockIoServiceImpl implements IWmsStockIoService {
// 执行入库操作(退库就是入库) // 执行入库操作(退库就是入库)
changeStock(returnDetail.getWarehouseId(), returnDetail.getItemType(), changeStock(returnDetail.getWarehouseId(), returnDetail.getItemType(),
returnDetail.getItemId(), returnDetail.getQuantity(), true, unit); returnDetail.getItemId(), returnDetail.getBatchNo(), returnDetail.getQuantity(), true, unit);
} }
// 更新单据状态为已审核2 // 更新单据状态为已审核2
returnStockIo.setStatus(2); returnStockIo.setStatus(2);
@@ -297,23 +297,24 @@ public class WmsStockIoServiceImpl implements IWmsStockIoService {
if (details == null || details.isEmpty()) { if (details == null || details.isEmpty()) {
throw new RuntimeException("单据明细不能为空"); throw new RuntimeException("单据明细不能为空");
} }
//如果details.batchNo不相等则需要去stock表新建一条批次号不同的记录
for (WmsStockIoDetail detail : details) { for (WmsStockIoDetail detail : details) {
String ioType = stockIo.getIoType(); String ioType = stockIo.getIoType();
if ("in".equals(ioType)) { if ("in".equals(ioType)) {
// 入库:目标库位库存增加 // 入库:目标库位库存增加
changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getQuantity(), true, detail.getUnit()); changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getBatchNo(), detail.getQuantity(), true, detail.getUnit());
} else if ("out".equals(ioType)) { } else if ("out".equals(ioType)) {
// 出库:目标库位库存减少 // 出库:目标库位库存减少
changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getQuantity(), false, detail.getUnit()); changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getBatchNo(), detail.getQuantity(), false, detail.getUnit());
} else if ("transfer".equals(ioType)) { } else if ("transfer".equals(ioType)) {
// 移库fromWarehouseId减少warehouseId增加 // 移库fromWarehouseId减少warehouseId增加
if (detail.getFromWarehouseId() == null) { if (detail.getFromWarehouseId() == null) {
throw new RuntimeException("移库明细缺少源库位ID"); throw new RuntimeException("移库明细缺少源库位ID");
} }
// 先减少源库位 // 先减少源库位
changeStock(detail.getFromWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getQuantity(), false, detail.getUnit()); changeStock(detail.getFromWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getBatchNo(), detail.getQuantity(), false, detail.getUnit());
// 再增加目标库位 // 再增加目标库位
changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getQuantity(), true, detail.getUnit()); changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getBatchNo(), detail.getQuantity(), true, detail.getUnit());
} else { } else {
throw new RuntimeException("未知的出入库类型"); throw new RuntimeException("未知的出入库类型");
} }
@@ -343,19 +344,18 @@ public class WmsStockIoServiceImpl implements IWmsStockIoService {
String ioType = stockIo.getIoType(); String ioType = stockIo.getIoType();
if ("in".equals(ioType)) { if ("in".equals(ioType)) {
// 入库撤销:目标库位库存减少 // 入库撤销:目标库位库存减少
// changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getBatchNo(), detail.getQuantity(), false, detail.getUnit()); changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getBatchNo(), detail.getQuantity(), false, detail.getUnit());
changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getQuantity(), false, detail.getUnit());
} else if ("out".equals(ioType)) { } else if ("out".equals(ioType)) {
// 出库撤销:目标库位库存增加 // 出库撤销:目标库位库存增加
changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getQuantity(), true, detail.getUnit()); changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getBatchNo(), detail.getQuantity(), true, detail.getUnit());
} else if ("transfer".equals(ioType)) { } else if ("transfer".equals(ioType)) {
if (detail.getFromWarehouseId() == null) { if (detail.getFromWarehouseId() == null) {
throw new ServiceException("移库明细缺少源库位ID"); throw new ServiceException("移库明细缺少源库位ID");
} }
// 源库位库存增加 // 源库位库存增加
changeStock(detail.getFromWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getQuantity(), true, detail.getUnit()); changeStock(detail.getFromWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getBatchNo(), detail.getQuantity(), true, detail.getUnit());
// 目标库位库存减少 // 目标库位库存减少
changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getQuantity(), false, detail.getUnit()); changeStock(detail.getWarehouseId(), detail.getItemType(), detail.getItemId(), detail.getBatchNo(), detail.getQuantity(), false, detail.getUnit());
} else { } else {
throw new ServiceException("未知的出入库类型"); throw new ServiceException("未知的出入库类型");
} }
@@ -427,12 +427,32 @@ public class WmsStockIoServiceImpl implements IWmsStockIoService {
* 库存增减isAdd=true为增加false为减少减少时校验库存是否足够 * 库存增减isAdd=true为增加false为减少减少时校验库存是否足够
*/ */
private void changeStock(Long warehouseId, String itemType, Long itemId, BigDecimal quantity, boolean isAdd, String unit) { private void changeStock(Long warehouseId, String itemType, Long itemId, BigDecimal quantity, boolean isAdd, String unit) {
WmsStock stock = stockMapper.selectOne(Wrappers.<WmsStock>lambdaQuery() changeStock(warehouseId, itemType, itemId, null, quantity, isAdd, unit);
.eq(WmsStock::getWarehouseId, warehouseId) }
.eq(WmsStock::getItemType, itemType)
.eq(WmsStock::getItemId, itemId) /**
// .eq(WmsStock::getBatchNo, batchNo) * 库存增减支持批次号isAdd=true为增加false为减少减少时校验库存是否足够
.last("limit 1")); */
private void changeStock(Long warehouseId, String itemType, Long itemId, String batchNo, BigDecimal quantity, boolean isAdd, String unit) {
WmsStock stock = null;
if (StringUtils.isNotBlank(batchNo)) {
// 如果指定了批次号,按批次号查找
stock = stockMapper.selectOne(Wrappers.<WmsStock>lambdaQuery()
.eq(WmsStock::getWarehouseId, warehouseId)
.eq(WmsStock::getItemType, itemType)
.eq(WmsStock::getItemId, itemId)
.eq(WmsStock::getBatchNo, batchNo)
.last("limit 1"));
} else {
// 如果没有指定批次号,查找任意一个批次
stock = stockMapper.selectOne(Wrappers.<WmsStock>lambdaQuery()
.eq(WmsStock::getWarehouseId, warehouseId)
.eq(WmsStock::getItemType, itemType)
.eq(WmsStock::getItemId, itemId)
.last("limit 1"));
}
if (stock == null) { if (stock == null) {
if (!isAdd) { if (!isAdd) {
throw new RuntimeException("库存不足,无法出库/移库"); throw new RuntimeException("库存不足,无法出库/移库");
@@ -442,18 +462,37 @@ public class WmsStockIoServiceImpl implements IWmsStockIoService {
stock.setWarehouseId(warehouseId); stock.setWarehouseId(warehouseId);
stock.setItemType(itemType); stock.setItemType(itemType);
stock.setItemId(itemId); stock.setItemId(itemId);
stock.setBatchNo("B-100"); stock.setBatchNo(StringUtils.isNotBlank(batchNo) ? batchNo : "B-100");
stock.setQuantity(quantity); stock.setQuantity(quantity);
stock.setUnit(unit); stock.setUnit(unit);
stockMapper.insert(stock); stockMapper.insert(stock);
} else { } else {
BigDecimal newQty = isAdd ? stock.getQuantity().add(quantity) : stock.getQuantity().subtract(quantity); // 如果指定了批次号且与现有库存批次号不同,需要新建记录
if (newQty.compareTo(BigDecimal.ZERO) < 0) { if (StringUtils.isNotBlank(batchNo) && !batchNo.equals(stock.getBatchNo())) {
throw new RuntimeException("库存不足,无法出库/移库"); if (!isAdd) {
throw new RuntimeException("指定批次号库存不足,无法出库/移库");
}
// 新建不同批次号的库存记录
WmsStock newStock = new WmsStock();
newStock.setWarehouseId(warehouseId);
newStock.setItemType(itemType);
newStock.setItemId(itemId);
newStock.setBatchNo(batchNo);
newStock.setQuantity(quantity);
newStock.setUnit(unit);
stockMapper.insert(newStock);
stock = newStock; // 更新stock引用用于日志记录
} else {
// 更新现有库存
BigDecimal newQty = isAdd ? stock.getQuantity().add(quantity) : stock.getQuantity().subtract(quantity);
if (newQty.compareTo(BigDecimal.ZERO) < 0) {
throw new RuntimeException("库存不足,无法出库/移库");
}
stock.setQuantity(newQty);
stockMapper.updateById(stock);
} }
stock.setQuantity(newQty);
stockMapper.updateById(stock);
} }
// 记录库存变更日志 // 记录库存变更日志
WmsStockLog log = new WmsStockLog(); WmsStockLog log = new WmsStockLog();
log.setWarehouseId(warehouseId); log.setWarehouseId(warehouseId);