feat(wms):出入库导入增加料号与规格型号/SKU码一致性校验
- 按料号查物料档案后逐项比对,任何一项不符直接报对应错误:规格型号/SKU码必须与档案完全一致(trim后比较) - Excel留空而档案有值、或Excel填值而档案为空,均视为不一致报错(提示Excel:空/档案:空) - SKU码以档案条码(bar_code)为比对基准;出库料号已填写但货主下查不到时直接报错,不再被SKU码/商品名称静默兜底(与入库对齐
This commit is contained in:
+10
-16
@@ -1827,8 +1827,6 @@ public class StockInOrderApplicationService {
|
|||||||
.collect(Collectors.groupingBy(r -> StringUtils.isBlank(r.getConsignmentNo()) ? "__EMPTY_CONSIGNMENT__" : r.getConsignmentNo()));
|
.collect(Collectors.groupingBy(r -> StringUtils.isBlank(r.getConsignmentNo()) ? "__EMPTY_CONSIGNMENT__" : r.getConsignmentNo()));
|
||||||
|
|
||||||
List<StockInOrderDO> orderList = new ArrayList<>();
|
List<StockInOrderDO> orderList = new ArrayList<>();
|
||||||
// 收集"料号与规格型号/SKU码不一致"的错误行,最后统一抛出,避免用户修一行导一次
|
|
||||||
List<String> consistencyErrors = new ArrayList<>();
|
|
||||||
for (Map.Entry<String, List<StockInOrderImportRowDTO>> entry : groupMap.entrySet()) {
|
for (Map.Entry<String, List<StockInOrderImportRowDTO>> entry : groupMap.entrySet()) {
|
||||||
List<StockInOrderImportRowDTO> groupRows = entry.getValue();
|
List<StockInOrderImportRowDTO> groupRows = entry.getValue();
|
||||||
StockInOrderImportRowDTO h = groupRows.get(0);
|
StockInOrderImportRowDTO h = groupRows.get(0);
|
||||||
@@ -2047,20 +2045,21 @@ public class StockInOrderApplicationService {
|
|||||||
log.error(errorMsg);
|
log.error(errorMsg);
|
||||||
throw new ServiceException(errorMsg);
|
throw new ServiceException(errorMsg);
|
||||||
}
|
}
|
||||||
// 校验料号与规格型号/SKU码的一致性:档案有值就必须一致(Excel留空视为不一致);档案为空则跳过该项
|
// 校验料号与规格型号/SKU码一致性:按料号查到档案后逐项比对,任何一项不符直接报对应错误
|
||||||
|
// 双方(trim后)必须完全一致:Excel留空而档案有值、或Excel填了值而档案为空,均视为不一致报错
|
||||||
String excelSpec = StringUtils.trimToEmpty(r.getSpecificationModel());
|
String excelSpec = StringUtils.trimToEmpty(r.getSpecificationModel());
|
||||||
if (StringUtils.isNotBlank(materialBaseInfoPO.getSpecificationModel())
|
String dbSpec = StringUtils.trimToEmpty(materialBaseInfoPO.getSpecificationModel());
|
||||||
&& !excelSpec.equals(materialBaseInfoPO.getSpecificationModel().trim())) {
|
if (!excelSpec.equals(dbSpec)) {
|
||||||
consistencyErrors.add(String.format("料号[%s](商品名称:%s)规格型号与物料档案不一致(Excel:%s / 档案:%s)",
|
throw new ServiceException(String.format("导入失败:料号[%s](商品名称:%s)规格型号与物料档案不一致(Excel:%s / 档案:%s)",
|
||||||
r.getMaterialCode(), r.getMaterialName(),
|
r.getMaterialCode(), r.getMaterialName(),
|
||||||
excelSpec.isEmpty() ? "空" : excelSpec, materialBaseInfoPO.getSpecificationModel().trim()));
|
excelSpec.isEmpty() ? "空" : excelSpec, dbSpec.isEmpty() ? "空" : dbSpec));
|
||||||
}
|
}
|
||||||
String excelSku = StringUtils.trimToEmpty(r.getSkuCode());
|
String excelSku = StringUtils.trimToEmpty(r.getSkuCode());
|
||||||
if (StringUtils.isNotBlank(materialBaseInfoPO.getBarCode())
|
String dbSku = StringUtils.trimToEmpty(materialBaseInfoPO.getBarCode());
|
||||||
&& !excelSku.equals(materialBaseInfoPO.getBarCode().trim())) {
|
if (!excelSku.equals(dbSku)) {
|
||||||
consistencyErrors.add(String.format("料号[%s](商品名称:%s)SKU码与物料档案不一致(Excel:%s / 档案:%s)",
|
throw new ServiceException(String.format("导入失败:料号[%s](商品名称:%s)SKU码与物料档案不一致(Excel:%s / 档案:%s)",
|
||||||
r.getMaterialCode(), r.getMaterialName(),
|
r.getMaterialCode(), r.getMaterialName(),
|
||||||
excelSku.isEmpty() ? "空" : excelSku, materialBaseInfoPO.getBarCode().trim()));
|
excelSku.isEmpty() ? "空" : excelSku, dbSku.isEmpty() ? "空" : dbSku));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数量已在前面检查过,这里直接使用
|
// 数量已在前面检查过,这里直接使用
|
||||||
@@ -2203,11 +2202,6 @@ public class StockInOrderApplicationService {
|
|||||||
if (orderList.isEmpty()) {
|
if (orderList.isEmpty()) {
|
||||||
throw new ServiceException("导入失败:所有入库单的明细行都因数据不完整(数量为空或物料基础信息缺失)被跳过,请检查Excel数据");
|
throw new ServiceException("导入失败:所有入库单的明细行都因数据不完整(数量为空或物料基础信息缺失)被跳过,请检查Excel数据");
|
||||||
}
|
}
|
||||||
// 存在料号与规格型号/SKU码不一致的明细行时,拒绝导入并一次性提示全部问题行
|
|
||||||
if (!consistencyErrors.isEmpty()) {
|
|
||||||
throw new ServiceException("导入失败,以下明细行的规格型号/SKU码与物料档案不一致,请修正后重新导入:\n"
|
|
||||||
+ String.join("\n", consistencyErrors));
|
|
||||||
}
|
|
||||||
|
|
||||||
return stockInOrderDomainService.batchInsert(orderList);
|
return stockInOrderDomainService.batchInsert(orderList);
|
||||||
|
|
||||||
|
|||||||
+17
-21
@@ -112,8 +112,7 @@ public class ExcelParseService {
|
|||||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||||
Long topOrganizationId = loginUser != null && loginUser.getUserPo() != null
|
Long topOrganizationId = loginUser != null && loginUser.getUserPo() != null
|
||||||
? loginUser.getUserPo().getTopOrganizationId() : null;
|
? loginUser.getUserPo().getTopOrganizationId() : null;
|
||||||
StringBuilder materialConsistencyErrors = new StringBuilder();
|
initList(itemList, warehouseId, warehouseCode, warehouseName, shipperId, topOrganizationId);
|
||||||
initList(itemList, warehouseId, warehouseCode, warehouseName, shipperId, topOrganizationId, materialConsistencyErrors);
|
|
||||||
stockOutOrder.setMaterialDetailList(itemList);
|
stockOutOrder.setMaterialDetailList(itemList);
|
||||||
stockOutOrder.setWarehouseName(warehouseName);
|
stockOutOrder.setWarehouseName(warehouseName);
|
||||||
stockOutOrder.setWarehouseCode(warehouseCode);
|
stockOutOrder.setWarehouseCode(warehouseCode);
|
||||||
@@ -171,10 +170,6 @@ public class ExcelParseService {
|
|||||||
for (String dateError : headerListener.getDateParseErrors()) {
|
for (String dateError : headerListener.getDateParseErrors()) {
|
||||||
errorMsg.append(dateError).append("; ");
|
errorMsg.append(dateError).append("; ");
|
||||||
}
|
}
|
||||||
// 物料一致性校验错误与必填校验错误合并,任一有错都不落库
|
|
||||||
if (materialConsistencyErrors.length() > 0) {
|
|
||||||
errorMsg.insert(0, materialConsistencyErrors);
|
|
||||||
}
|
|
||||||
if (errorMsg.length() > 0) {
|
if (errorMsg.length() > 0) {
|
||||||
return errorMsg;
|
return errorMsg;
|
||||||
} else {
|
} else {
|
||||||
@@ -425,7 +420,8 @@ public class ExcelParseService {
|
|||||||
* @param shipperId 货主ID(用于过滤物料基础信息,确保查询到的是该货主绑定的物料)
|
* @param shipperId 货主ID(用于过滤物料基础信息,确保查询到的是该货主绑定的物料)
|
||||||
* @param topOrganizationId 一级组织ID(用于过滤物料基础信息)
|
* @param topOrganizationId 一级组织ID(用于过滤物料基础信息)
|
||||||
*/
|
*/
|
||||||
private void initList(List<OutMaterialDetailDO> outMaterialDetailDOList, Long warehouseId, String warehouseCode, String warehouseName, Long shipperId, Long topOrganizationId, StringBuilder materialConsistencyErrors) { for (OutMaterialDetailDO outMaterialDetailDO : outMaterialDetailDOList) {
|
private void initList(List<OutMaterialDetailDO> outMaterialDetailDOList, Long warehouseId, String warehouseCode, String warehouseName, Long shipperId, Long topOrganizationId) {
|
||||||
|
for (OutMaterialDetailDO outMaterialDetailDO : outMaterialDetailDOList) {
|
||||||
outMaterialDetailDO.setWarehouseId(warehouseId);
|
outMaterialDetailDO.setWarehouseId(warehouseId);
|
||||||
outMaterialDetailDO.setWarehouseCode(warehouseCode);
|
outMaterialDetailDO.setWarehouseCode(warehouseCode);
|
||||||
outMaterialDetailDO.setWarehouseName(warehouseName);
|
outMaterialDetailDO.setWarehouseName(warehouseName);
|
||||||
@@ -457,25 +453,25 @@ public class ExcelParseService {
|
|||||||
if (materialList != null && !materialList.isEmpty()) {
|
if (materialList != null && !materialList.isEmpty()) {
|
||||||
materialBaseInfoPO = materialList.get(0);
|
materialBaseInfoPO = materialList.get(0);
|
||||||
materialBaseInfoId = materialBaseInfoPO.getMaterialBaseInfoId();
|
materialBaseInfoId = materialBaseInfoPO.getMaterialBaseInfoId();
|
||||||
// ==== 新增:料号与规格型号/SKU码一致性校验(档案有值就必须一致,Excel留空视为不一致;档案为空跳过)====
|
BigDecimal unitPrice = materialBaseInfoPO.getUnitPrice();
|
||||||
|
outMaterialDetailDO.setUnitPrice(unitPrice);
|
||||||
|
// ==== 料号与规格型号/SKU码一致性校验:任何一项不符直接报对应错误 ====
|
||||||
|
// 双方(trim后)必须完全一致:Excel留空而档案有值、或Excel填了值而档案为空,均视为不一致报错
|
||||||
String excelSpec = StringUtils.trimToEmpty(outMaterialDetailDO.getSpecificationModel());
|
String excelSpec = StringUtils.trimToEmpty(outMaterialDetailDO.getSpecificationModel());
|
||||||
if (StringUtils.isNotBlank(materialBaseInfoPO.getSpecificationModel())
|
String dbSpec = StringUtils.trimToEmpty(materialBaseInfoPO.getSpecificationModel());
|
||||||
&& !excelSpec.equals(materialBaseInfoPO.getSpecificationModel().trim())) {
|
if (!excelSpec.equals(dbSpec)) {
|
||||||
materialConsistencyErrors.append("料号「").append(outMaterialDetailDO.getMaterialNo())
|
throw new ServiceException(String.format("导入失败:料号「%s」规格型号与物料档案不一致(Excel:%s / 档案:%s)",
|
||||||
.append("」规格型号与物料档案不一致(Excel:").append(excelSpec.isEmpty() ? "空" : excelSpec)
|
materialNo, excelSpec.isEmpty() ? "空" : excelSpec, dbSpec.isEmpty() ? "空" : dbSpec));
|
||||||
.append(" / 档案:").append(materialBaseInfoPO.getSpecificationModel().trim()).append("); ");
|
|
||||||
}
|
}
|
||||||
String excelSku = StringUtils.trimToEmpty(outMaterialDetailDO.getSkucode());
|
String excelSku = StringUtils.trimToEmpty(outMaterialDetailDO.getSkucode());
|
||||||
if (StringUtils.isNotBlank(materialBaseInfoPO.getBarCode())
|
String dbSku = StringUtils.trimToEmpty(materialBaseInfoPO.getBarCode());
|
||||||
&& !excelSku.equals(materialBaseInfoPO.getBarCode().trim())) {
|
if (!excelSku.equals(dbSku)) {
|
||||||
materialConsistencyErrors.append("料号「").append(outMaterialDetailDO.getMaterialNo())
|
throw new ServiceException(String.format("导入失败:料号「%s」SKU码与物料档案不一致(Excel:%s / 档案:%s)",
|
||||||
.append("」SKU码与物料档案不一致(Excel:").append(excelSku.isEmpty() ? "空" : excelSku)
|
materialNo, excelSku.isEmpty() ? "空" : excelSku, dbSku.isEmpty() ? "空" : dbSku));
|
||||||
.append(" / 档案:").append(materialBaseInfoPO.getBarCode().trim()).append("); ");
|
|
||||||
}
|
}
|
||||||
}else {
|
} else {
|
||||||
// 料号已填写但在该货主下查不到 → 直接报错(与入库导入一致),不再被SKU码/商品名称静默兜底
|
// 料号已填写但在该货主下查不到 → 直接报错(与入库导入一致),不再被SKU码/商品名称静默兜底
|
||||||
materialConsistencyErrors.append("料号「").append(materialNo)
|
throw new ServiceException(String.format("导入失败:料号「%s」在当前客户(货主)下不存在,请核对料号或在物料管理中维护", materialNo));
|
||||||
.append("」在当前客户(货主)下不存在,请核对料号或在物料管理中维护;");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user