diff --git a/src/main/java/com/xujie/modules/inspection/service/impl/InspectionRequestServiceImpl.java b/src/main/java/com/xujie/modules/inspection/service/impl/InspectionRequestServiceImpl.java index 3e7dd27..2b308c0 100644 --- a/src/main/java/com/xujie/modules/inspection/service/impl/InspectionRequestServiceImpl.java +++ b/src/main/java/com/xujie/modules/inspection/service/impl/InspectionRequestServiceImpl.java @@ -340,22 +340,22 @@ public class InspectionRequestServiceImpl extends ServiceImpl existingSubList = inspectionRequestDetailSubMapper.selectByRequestNo(site, requestNo); - + Map existingSubMap = new HashMap<>(); Map existingDetailMap = new HashMap<>(); - + for (InspectionRequestDetailSub sub : existingSubList) { String key = sub.getPoNo() + "|" + sub.getPoItemNo(); existingSubMap.put(key, sub); } - + List existingDetailList = inspectionRequestDetailMapper.selectByRequestNo(site, requestNo); for (InspectionRequestDetail detail : existingDetailList) { // Detail没有直接存储PO信息,需要通过itemNo关联 // 这里先构建 itemNo -> Detail 的映射 } - + // 构建 itemNo -> Detail 的映射(用于后续更新) Map itemNoToDetailMap = new HashMap<>(); for (InspectionRequestDetail detail : existingDetailList) { @@ -381,23 +381,23 @@ public class InspectionRequestServiceImpl extends ServiceImpl> entry : newItemsGroupMap.entrySet()) { String productKey = entry.getKey(); List newItemsList = entry.getValue(); - + // 计算本次新增的总数量 BigDecimal newTotalQty = BigDecimal.ZERO; for (InspectionRequestItemVO item : newItemsList) { newTotalQty = newTotalQty.add(item.getQty()); } - + InspectionRequestItemVO firstItem = newItemsList.get(0); - + // 6. 判断该产品是否已存在于明细中 InspectionRequestDetailSub existingSub = existingSubMap.get(productKey); - + if (existingSub != null) { // 【情况A】产品已存在,需要累加数量到已有明细 log.info("产品已存在,累加数量: productKey={}, 原有数量={}, 新增数量={}", productKey, existingSub.getQty(), newTotalQty); - + // 6.1 锁定PO的验货数量(只锁定本次新增的数量) int updateCount = poDetailMapper.lockInspectQty( site, @@ -405,7 +405,7 @@ public class InspectionRequestServiceImpl extends ServiceImpl subUpdateWrapper = new UpdateWrapper<>(); subUpdateWrapper.eq("site", site) .eq("request_no", requestNo) .eq("item_no", existingSub.getItemNo()) .eq("po_no", firstItem.getOrderNo()) .eq("po_item_no", firstItem.getItemNo()); - + InspectionRequestDetailSub updateSub = new InspectionRequestDetailSub(); updateSub.setQty(updatedQty); inspectionRequestDetailSubMapper.update(updateSub, subUpdateWrapper); - + // 6.3 更新Detail表的数量(累加) InspectionRequestDetail existingDetail = itemNoToDetailMap.get(existingSub.getItemNo()); if (existingDetail != null) { @@ -435,26 +435,26 @@ public class InspectionRequestServiceImpl extends ServiceImpl poInfo = poDetailMapper.getPoDetailInspectInfo( site, firstItem.getOrderNo(), firstItem.getItemNo()); - + // 锁定验货数量 int updateCount = poDetailMapper.lockInspectQty( site, @@ -462,7 +462,7 @@ public class InspectionRequestServiceImpl extends ServiceImpl oldSubList = inspectionRequestDetailSubMapper.selectByRequestNo(site, requestNo); - + // 构建旧明细的数量映射:key = orderNo + "|" + itemNo, value = qty Map oldQtyMap = new HashMap<>(); for (InspectionRequestDetailSub sub : oldSubList) { @@ -600,23 +600,23 @@ public class InspectionRequestServiceImpl extends ServiceImpl> entry : itemsGroupMap.entrySet()) { String productKey = entry.getKey(); List itemsList = entry.getValue(); - + // 计算该产品的总数量(累加) BigDecimal totalQty = BigDecimal.ZERO; for (InspectionRequestItemVO item : itemsList) { totalQty = totalQty.add(item.getQty()); } - + // 使用第一条数据的其他字段 InspectionRequestItemVO firstItem = itemsList.get(0); - + // 数据校验:数量必须为正数 if (totalQty.compareTo(BigDecimal.ZERO) <= 0) { throw new RuntimeException( "PO:" + firstItem.getOrderNo() + " 行:" + firstItem.getItemNo() + " 的验货数量必须大于0" ); } - + // 锁定验货数量(使用合并后的总数量) int updateCount = poDetailMapper.lockInspectQty( site, @@ -1131,7 +1131,7 @@ public class InspectionRequestServiceImpl extends ServiceImpl poInfo = poDetailMapper.getPoDetailByOrderRef(site, dto.getPoNo(), dto.getPoItemNo()); if (poInfo == null) { throw new RuntimeException(String.format( - "第%d行:PO号 %s 行号 %s 不存在,请检查外部订单号(order_ref1)和外部行号(order_ref2)", + "第%d行:PO号 %s 行号 %s 不存在,请检查外部订单号", rowNum, dto.getPoNo(), dto.getPoItemNo())); } diff --git a/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java b/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java index c06737a..9a6aa0f 100644 --- a/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java +++ b/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java @@ -228,6 +228,10 @@ public class QcServiceImpl implements QcService { }else if ("***".equals(data.getInspectionTypeNo())) { data.setItemNo("PF-" + itemNo); } + // 检验类型不在编码规则内时直接报错,避免 ItemNo 为空导致 INSERT 失败 + if (StringUtils.isBlank(data.getItemNo())) { + throw new RuntimeException("未知的检验类型编码:" + data.getInspectionTypeNo() + ",无法生成项目编码!"); + } List checkItemOnlyOne = qcMapper.checkItemOnlyOne(data); if (!checkItemOnlyOne.isEmpty()) { throw new RuntimeException("该检验项目已存在!"); @@ -315,13 +319,25 @@ public class QcServiceImpl implements QcService { QcItemData task = null; // 遍历每一行(从第二行开始) for (int j = 1; j < rows; j++) { - // 实例化对象 - task = new QcItemData(); //获得该行 XSSFRow row = sheet.getRow(j); + if (row == null) { + continue; + } + // 读取关键列(不能用 getRawValue,文本单元格它返回的是共享字符串表索引而非真实文本) + String itemDesc = getCellStringValue(row.getCell(0)); + String inspectionTypeNo = getCellStringValue(row.getCell(3)); + // 关键列均为空视为空行,跳过(避免模板残留空行导致插入失败) + if (StringUtils.isBlank(itemDesc) && StringUtils.isBlank(inspectionTypeNo)) { + continue; + } + // 实例化对象 + task = new QcItemData(); // 为对象赋值 QcSiteBuHelper.resolveSiteParam(data.getSite(), task::setSite, task::setBuNo); - task.setInspectionTypeNo(row.getCell(3).getRawValue()); + // itemType 必须在 getItemNo 之前设置,否则按类型查不到已有编码,每行都会生成相同编码 + task.setItemType("D"); + task.setInspectionTypeNo(inspectionTypeNo); // 获取编码 String itemNo = qcMapper.getItemNo(task); if ("101".equals(task.getInspectionTypeNo()) || "102".equals(task.getInspectionTypeNo()) || "103".equals(task.getInspectionTypeNo()) || "104".equals(task.getInspectionTypeNo())) { @@ -334,36 +350,40 @@ public class QcServiceImpl implements QcService { task.setItemNo("FQC-" + itemNo); } else if ("108".equals(task.getInspectionTypeNo())) { task.setItemNo("PQC-" + itemNo); + } else if ("GX".equals(task.getInspectionTypeNo())) { + task.setItemNo("GX-" + itemNo); + } else if ("***".equals(task.getInspectionTypeNo())) { + task.setItemNo("PF-" + itemNo); + } + // 检验类型编码无效时明确报错,避免 ItemNo 为空导致 INSERT 失败 + if (StringUtils.isBlank(task.getItemNo())) { + throw new RuntimeException("第" + (j + 1) + "行检验类型编码无效:" + task.getInspectionTypeNo()); + } + if (StringUtils.isBlank(itemDesc)) { + throw new RuntimeException("第" + (j + 1) + "行检验项目描述不能为空!"); } - task.setItemDesc(row.getCell(0).getStringCellValue()); - task.setValueType(row.getCell(1).getStringCellValue()); - if (row.getCell(1).getStringCellValue().equals("文本")){ + task.setItemDesc(itemDesc.trim()); + String valueType = getCellStringValue(row.getCell(1)); + if (StringUtils.isBlank(valueType)) { + throw new RuntimeException("第" + (j + 1) + "行值类型不能为空!"); + } + task.setValueType(valueType); + if (valueType.equals("文本")){ task.setValueTypeDb("T"); task.setMaxValue(null); task.setMinValue(null); - } else if (row.getCell(1).getStringCellValue().equals("数字")) { + } else if (valueType.equals("数字")) { task.setValueTypeDb("N"); - if (row.getCell(3) == null) { - task.setMaxValue(null); - } else { - task.setMaxValue(BigDecimal.valueOf(row.getCell(3).getNumericCellValue())); - } - if (row.getCell(4) == null) { - task.setMinValue(null); - } else { - task.setMinValue(BigDecimal.valueOf(row.getCell(4).getNumericCellValue())); - } - } else { - task.setValueTypeDb(null); - } - if (row.getCell(2) == null) { - task.setDefaultValue(null); + String maxValue = getCellStringValue(row.getCell(4)); + task.setMaxValue(StringUtils.isBlank(maxValue) ? null : new BigDecimal(maxValue.trim())); + String minValue = getCellStringValue(row.getCell(5)); + task.setMinValue(StringUtils.isBlank(minValue) ? null : new BigDecimal(minValue.trim())); } else { - task.setDefaultValue(row.getCell(2).getRawValue()); + throw new RuntimeException("第" + (j + 1) + "行值类型无效:" + valueType + "(只能填写 文本 或 数字)"); } - task.setItemType("D"); + task.setDefaultValue(getCellStringValue(row.getCell(2))); task.setCreatedBy(data.getCreateBy()); - task.setMethodNo(row.getCell(5).getRawValue()); + task.setMethodNo(getCellStringValue(row.getCell(6))); // 新增 qcMapper.qcItemSave(task); // 新增项目里的方法 @@ -374,6 +394,35 @@ public class QcServiceImpl implements QcService { } } + /** + * 读取单元格的实际文本值。 + * 不能直接使用 getRawValue():对文本单元格它返回的是共享字符串表的索引而不是真实文本; + * 这里按单元格类型分别取值,保证拿到用户在 Excel 中看到的内容。 + **/ + private String getCellStringValue(XSSFCell cell) { + if (cell == null) { + return null; + } + CellType cellType = cell.getCellType(); + if (cellType == CellType.FORMULA) { + cellType = cell.getCachedFormulaResultType(); + } + switch (cellType) { + case STRING: + return cell.getStringCellValue(); + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + return new SimpleDateFormat("yyyy-MM-dd").format(cell.getDateCellValue()); + } + // 按单元格显示格式取值,避免出现 105.0、科学计数法等格式偏差 + return new DataFormatter().formatCellValue(cell).trim(); + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + default: + return null; + } + } + // ======================= 质检员信息维护 ======================= /**