fix(oms): 出入库导入行级必填校验+页签解析失败完整堆栈日志

一、行级必填校验(ReservationStockInOrderImpl)
- 入库导入:新增校验空【產品編號】/空【支/件数】的明细行,给出明确提示
- 出库导入:新增校验空【支/件数】的明细行
- 修复原因:明细行件数为空时 new BigDecimal(null) 抛无信息的 NullPointerException,页面只显示 页签[x]:java.lang.NullPointerException 无法定位

二、页签解析失败完整堆栈日志
- 出/入库多页签解析第一阶段捕获异常时,将完整堆栈打入服务端日志(LOGGER.error),便于远程定位页签内具体报错行号
This commit is contained in:
rcx
2026-09-07 14:18:34 +08:00
parent 1c4b520f5a
commit 34b27eabd2
@@ -336,6 +336,12 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
if (productDetailList.isEmpty()) {
throw new Exception("未解析到产品明细数据,请检查模板中是否填写了產品編號");
}
// 行级必填校验:支数缺失的行直接给出明确提示,避免后续 new BigDecimal(null) 抛无信息的NPE
for (ProductDetail productDetail : productDetailList) {
if (productDetail.getPieceCount() == null) {
throw new Exception("产品[" + productDetail.getProductCode() + "]的【支/件数】未填写,请补全后重新导入");
}
}
LOGGER.info("页签[{}]解析完成,货品明细{}条,客户配送明细{}条",
sheetName, productDetailList.size(), customerDeliveryDetailList.size());
@@ -658,6 +664,9 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
preparedOrders.add(prepared); // null=空页签,跳过
}
} catch (Exception e) {
// 完整堆栈进服务端日志,便于定位页签内解析异常的具体行号
LOGGER.error("页签[{}]入库导入解析失败", name, e);
// 非模板页签的解析异常(如NPE)message 可能为空,兜底用异常类名,避免报错显示"页签[x]null"
sheetProblems.add("页签[" + name + "]" + (e.getMessage() == null ? e.toString() : e.getMessage()));
}
}
@@ -710,6 +719,15 @@ public class ReservationStockInOrderImpl extends ServiceImpl<ReservationStockInO
if (productDetailList == null || productDetailList.isEmpty()) {
return null;
}
// 行级必填校验:编号/支数缺失的行直接给出明确提示,避免后续 new BigDecimal(null) 抛无信息的NPE
for (StockInProductDetail productDetail : productDetailList) {
if (productDetail.getProductCode() == null || productDetail.getProductCode().trim().isEmpty()) {
throw new ServiceException("存在未填写【產品編號】的明细行,请补全后重新导入");
}
if (productDetail.getPieceCount() == null) {
throw new ServiceException("产品[" + productDetail.getProductCode() + "]的【支/件数】未填写,请补全后重新导入");
}
}
StockInHeader stockInHeader = resultDTO.getStockInHeader();
// ====== 第一步:物料编号存在性校验(模板只填物料编号即可,名称按编号自动匹配) ======
// 查询结果为空说明库中没有该物料,先收集全部缺失编号,不立即报错