diff --git a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java index 0bd9c89b..e2caf314 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelServiceImpl.java @@ -492,7 +492,11 @@ public class CoDelServiceImpl implements CoDelService { data.getCmcInvoice()+"】订单取消" + ""; String textHead = data.getCmcInvoice()+"【发票:"+ data.getCmcInvoice()+"】订单取消"; String[] mailAddress = coDelMapper.queryUsersByRoleName("关务仓库",data.getSite()).stream().map(SysUserEntity::getEmail).toArray(String[]::new); - String[] mailAddress2 = new String[]{coDelMapper.queryByUserName(data.getCreateBy()).getEmail()}; + + // 安全获取创建人邮箱,防止用户不存在或邮箱为空的空指针异常 + SysUserEntity creator = coDelMapper.queryByUserName(data.getCreateBy()); + String[] mailAddress2 = (creator != null && creator.getEmail() != null) ? + new String[]{creator.getEmail()} : new String[]{}; String[] mailAddressAll = ArrayUtils.addAll(mailAddress, mailAddress2); if (mailAddressAll.length>0) { sendMailUtil(textHead, text,mailAddressAll, data); @@ -512,7 +516,11 @@ public class CoDelServiceImpl implements CoDelService { data.getCmcInvoice()+"】取消废弃,恢复正常" + ""; String textHead = data.getCmcInvoice()+"【发票:"+ data.getCmcInvoice()+"】取消废弃"; String[] mailAddress = coDelMapper.queryUsersByRoleName("关务仓库",data.getSite()).stream().map(SysUserEntity::getEmail).toArray(String[]::new); - String[] mailAddress2 = new String[]{coDelMapper.queryByUserName(data.getCreateBy()).getEmail()}; + + // 安全获取创建人邮箱,防止用户不存在或邮箱为空的空指针异常 + SysUserEntity creator = coDelMapper.queryByUserName(data.getCreateBy()); + String[] mailAddress2 = (creator != null && creator.getEmail() != null) ? + new String[]{creator.getEmail()} : new String[]{}; String[] mailAddressAll = ArrayUtils.addAll(mailAddress, mailAddress2); if (mailAddressAll.length>0) { sendMailUtil(textHead, text,mailAddressAll, data); @@ -643,7 +651,11 @@ public class CoDelServiceImpl implements CoDelService { +" 变更后数量:"+data.getQty()+""; String textHead = data.getDelNo()+"【发票:"+ data.getCmcInvoice()+"】改单[发货数量变更]"; String[] mailAddress = coDelMapper.queryUsersByRoleName("关务仓库",data.getSite()).stream().map(SysUserEntity::getEmail).toArray(String[]::new); - String[] mailAddress2 = new String[]{coDelMapper.queryByUserName(checkHeader.get(0).getCreateBy()).getEmail()}; + + // 安全获取创建人邮箱,防止用户不存在或邮箱为空的空指针异常 + SysUserEntity creator = coDelMapper.queryByUserName(checkHeader.get(0).getCreateBy()); + String[] mailAddress2 = (creator != null && creator.getEmail() != null) ? + new String[]{creator.getEmail()} : new String[]{}; String[] mailAddressAll = ArrayUtils.addAll(mailAddress, mailAddress2); if (mailAddressAll.length>0) { sendMailUtil(textHead, text,mailAddressAll, checkHeader.get(0)); @@ -666,7 +678,11 @@ public class CoDelServiceImpl implements CoDelService { " 新增发货"; String textHead = data.getDelNo()+"【发票:"+ data.getCmcInvoice()+"】改单[新增发货]"; String[] mailAddress = coDelMapper.queryUsersByRoleName("关务仓库",data.getSite()).stream().map(SysUserEntity::getEmail).toArray(String[]::new); - String[] mailAddress2 = new String[]{coDelMapper.queryByUserName(checkHeader.get(0).getCreateBy()).getEmail()}; + + // 安全获取创建人邮箱,防止用户不存在或邮箱为空的空指针异常 + SysUserEntity creator = coDelMapper.queryByUserName(checkHeader.get(0).getCreateBy()); + String[] mailAddress2 = (creator != null && creator.getEmail() != null) ? + new String[]{creator.getEmail()} : new String[]{}; String[] mailAddressAll = ArrayUtils.addAll(mailAddress, mailAddress2); if (mailAddressAll.length>0) { sendMailUtil(textHead, text,mailAddressAll, checkHeader.get(0)); @@ -703,7 +719,11 @@ public class CoDelServiceImpl implements CoDelService { " 取消发货"; String textHead = data.getDelNo()+"【发票:"+ data.getCmcInvoice()+"】改单[取消发货]"; String[] mailAddress = coDelMapper.queryUsersByRoleName("关务仓库",data.getSite()).stream().map(SysUserEntity::getEmail).toArray(String[]::new); - String[] mailAddress2 = new String[]{coDelMapper.queryByUserName(checkHeader.get(0).getCreateBy()).getEmail()}; + + // 安全获取创建人邮箱,防止用户不存在或邮箱为空的空指针异常 + SysUserEntity creator = coDelMapper.queryByUserName(checkHeader.get(0).getCreateBy()); + String[] mailAddress2 = (creator != null && creator.getEmail() != null) ? + new String[]{creator.getEmail()} : new String[]{}; String[] mailAddressAll = ArrayUtils.addAll(mailAddress, mailAddress2); if (mailAddressAll.length>0) { sendMailUtil(textHead, text,mailAddressAll, checkHeader.get(0)); @@ -725,8 +745,15 @@ public class CoDelServiceImpl implements CoDelService { //设置邮件内容 String text = "" + "
发货通知单" +data.getDelNo()+"【发票:"+ data.getCmcInvoice()+"】仓库已确认" + "
"; String textHead = "发货通知单"+data.getDelNo()+"【发票:"+ data.getCmcInvoice()+"】仓库已确认"; - String[] mailAddress = new String[]{coDelMapper.queryByUserName(checkHeader.get(0).getCreateBy()).getEmail()}; - sendMailUtil(textHead, text, mailAddress, data); + + // 安全获取创建人邮箱,防止用户不存在或邮箱为空的空指针异常 + SysUserEntity creator = coDelMapper.queryByUserName(checkHeader.get(0).getCreateBy()); + if (creator != null && creator.getEmail() != null && !creator.getEmail().trim().isEmpty()) { + String[] mailAddress = new String[]{creator.getEmail()}; + sendMailUtil(textHead, text, mailAddress, data); + } else { + log.warn("仓库确认邮件发送失败:创建人{}不存在或邮箱为空", checkHeader.get(0).getCreateBy()); + } } @Override @@ -782,20 +809,24 @@ public class CoDelServiceImpl implements CoDelService { // 先删除全部明细,再新建明细 coDelMapper.deleteAllEcssDelDetail(headerData); - // 构建原数据Map,用于比较数量是否变化 - Map originalQtyMap = dbData.stream() - .collect(Collectors.toMap(EcssCoDelNotifyDetail::getPn, EcssCoDelNotifyDetail::getQty)); + // 构建原数据Map,使用itemNo作为唯一标识 + // 注意:不能用pn作为key,因为同一个pn可能有多行记录,每行都需要独立比较 + Map originalDataMap = dbData.stream() + .collect(Collectors.toMap(EcssCoDelNotifyDetail::getItemNo, detail -> detail, (v1, v2) -> v1)); for (int i = 0; i < excelList.size(); i++) { excelList.get(i).setDelNo(headerData.getDelNo()); excelList.get(i).setItemNo(i + 1); excelList.get(i).setModifyFlag(true); - // 判断数量是否变化:新增物料或数量不同时设置 modifyQtyFlag=true - String pn = excelList.get(i).getPn(); - BigDecimal newQty = excelList.get(i).getQty(); - if (!originalQtyMap.containsKey(pn) || - !originalQtyMap.get(pn).equals(newQty)) { + // 判断数量是否变化:按itemNo匹配原数据,比较同一行的数量是否变化 + Integer itemNo = i + 1; + EcssCoDelNotifyDetailData originalDetail = originalDataMap.get(itemNo); + + // 如果原数据中不存在该itemNo(新增行),或者pn不同(换料),或者数量不同,则标记modifyQtyFlag=true + if (originalDetail == null || + !originalDetail.getPn().equals(excelList.get(i).getPn()) || + !originalDetail.getQty().equals(excelList.get(i).getQty())) { excelList.get(i).setModifyQtyFlag(true); } } @@ -810,10 +841,16 @@ public class CoDelServiceImpl implements CoDelService { String textHead = headerData.getDelNo()+"【发票:"+ headerData.getCmcInvoice()+"】改单"; String[] mailAddress = coDelMapper.queryUsersByRoleName("关务仓库",headerData.getSite()).stream().map(SysUserEntity::getEmail).toArray(String[]::new); - String[] mailAddress2 = new String[]{coDelMapper.queryByUserName(headerData.getCreateBy()).getEmail()}; + + // 安全获取创建人邮箱,防止用户不存在或邮箱为空的空指针异常 + SysUserEntity creator = coDelMapper.queryByUserName(headerData.getCreateBy()); + String[] mailAddress2 = (creator != null && creator.getEmail() != null) ? + new String[]{creator.getEmail()} : new String[]{}; + // 合并 + 去重 String[] mailAddressAll = Stream.concat(Arrays.stream(mailAddress), Arrays.stream(mailAddress2)) .filter(Objects::nonNull) // 防止 null + .filter(email -> !email.trim().isEmpty()) // 过滤空字符串 .distinct() // 去重 .toArray(String[]::new); if (mailAddressAll.length>0) { @@ -832,8 +869,30 @@ public class CoDelServiceImpl implements CoDelService { List dbData, List newData) { StringBuilder emailContent = new StringBuilder(); - emailContent.append("
发货通知单").append(newHeaderData.getDelNo()) - .append("【发票:").append(newHeaderData.getCmcInvoice()).append("】改单
"); + + // HTML头部和样式 + emailContent.append(""); + emailContent.append(""); + emailContent.append(""); + emailContent.append(""); + emailContent.append(""); + emailContent.append(""); + emailContent.append(""); + + // 邮件标题 + emailContent.append("

发货通知单改单通知

"); + emailContent.append("

发货通知单号:").append(newHeaderData.getDelNo()).append("

"); + emailContent.append("

发票号:").append(newHeaderData.getCmcInvoice()).append("

"); + emailContent.append("

操作时间:").append(DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss")).append("

"); // 检查头表字段变更 StringBuilder headerChanges = new StringBuilder(); @@ -846,8 +905,8 @@ public class CoDelServiceImpl implements CoDelService { DateUtils.format(originalHeaderData.getReadyDate(), "yyyy-MM-dd") : "无"; String newDate = newHeaderData.getReadyDate() != null ? DateUtils.format(newHeaderData.getReadyDate(), "yyyy-MM-dd") : "无"; - headerChanges.append("
  • Ready Date: ") - .append(originalDate).append(" → ").append(newDate).append("
  • "); + headerChanges.append("
  • Ready Date: ") + .append(originalDate).append(" → ").append(newDate).append("
  • "); } // 检查ShippingMode变更 @@ -855,8 +914,8 @@ public class CoDelServiceImpl implements CoDelService { hasHeaderChanges = true; String originalMode = originalHeaderData.getShippingMode() != null ? originalHeaderData.getShippingMode() : "无"; String newMode = newHeaderData.getShippingMode() != null ? newHeaderData.getShippingMode() : "无"; - headerChanges.append("
  • Shipping Mode: ") - .append(originalMode).append(" → ").append(newMode).append("
  • "); + headerChanges.append("
  • Shipping Mode: ") + .append(originalMode).append(" → ").append(newMode).append("
  • "); } // 检查Destination变更 @@ -864,87 +923,105 @@ public class CoDelServiceImpl implements CoDelService { hasHeaderChanges = true; String originalDest = originalHeaderData.getDestination() != null ? originalHeaderData.getDestination() : "无"; String newDest = newHeaderData.getDestination() != null ? newHeaderData.getDestination() : "无"; - headerChanges.append("
  • Destination: ") - .append(originalDest).append(" → ").append(newDest).append("
  • "); + headerChanges.append("
  • Destination: ") + .append(originalDest).append(" → ").append(newDest).append("
  • "); } // 如果有头表字段变更,添加到邮件内容 if (hasHeaderChanges) { - emailContent.append("
    头表字段变更
    ") - .append("
      ").append(headerChanges).append("
    "); - } - - // 处理明细变更 - Map> dbMap = dbData.stream().collect(Collectors.groupingBy(EcssCoDelNotifyDetail::getPn)); - Map> newMap = newData.stream().collect(Collectors.groupingBy(EcssCoDelNotifyDetail::getPn)); - - // 构建原数据明细 - StringBuilder originalDetails = new StringBuilder(); - originalDetails.append("
      "); - for (EcssCoDelNotifyDetailData detail : dbData) { - if (!newMap.containsKey(detail.getPn())) { - // 删除的项目用红色显示 - originalDetails.append("
    1. ") - .append("PN:").append(detail.getPn()).append(" 数量:") - .append(detail.getQty().setScale(0, RoundingMode.HALF_UP)) - .append(" [已删除]
    2. "); - } else { - // 检查数量是否有变更 - EcssCoDelNotifyDetailData newDetail = newMap.get(detail.getPn()).get(0); - if (!detail.getQty().equals(newDetail.getQty())) { - // 数量有变更,用红色显示 - originalDetails.append("
    3. ") - .append("PN:").append(detail.getPn()).append(" 数量:") - .append(detail.getQty().setScale(0, RoundingMode.HALF_UP)) - .append("
    4. "); - } else { - // 无变更 - originalDetails.append("
    5. ") - .append("PN:").append(detail.getPn()).append(" 数量:") - .append(detail.getQty().setScale(0, RoundingMode.HALF_UP)) - .append("
    6. "); - } - } + emailContent.append("
      头表字段变更
      "); + emailContent.append("
        ").append(headerChanges).append("
      "); } - originalDetails.append("
    "); - - // 构建新数据明细 - StringBuilder newDetails = new StringBuilder(); - newDetails.append("
      "); - for (EcssCoDelNotifyDetailData detail : newData) { - if (!dbMap.containsKey(detail.getPn())) { - // 新增的项目用红色显示 - newDetails.append("
    1. ") - .append("PN:").append(detail.getPn()).append(" 数量:") - .append(detail.getQty().setScale(0, RoundingMode.HALF_UP)) - .append(" [新增]
    2. "); - } else { - // 检查数量是否有变更 - EcssCoDelNotifyDetailData originalDetail = dbMap.get(detail.getPn()).get(0); - if (!detail.getQty().equals(originalDetail.getQty())) { - // 数量有变更,用红色显示 - newDetails.append("
    3. ") - .append("PN:").append(detail.getPn()).append(" 数量:") - .append(detail.getQty().setScale(0, RoundingMode.HALF_UP)) - .append("
    4. "); - } else { - // 无变更 - newDetails.append("
    5. ") - .append("PN:").append(detail.getPn()).append(" 数量:") - .append(detail.getQty().setScale(0, RoundingMode.HALF_UP)) - .append("
    6. "); - } - } - } - newDetails.append("
    "); - // 添加明细变更到邮件内容 - String oldText = "
    原数据
    " + originalDetails + "
    "; - String newText = "
    新数据
    " + newDetails + "
    "; - emailContent.append(oldText).append(newText); + // 处理明细变更 - 生成对比表格 + emailContent.append("
    明细数据对比
    "); + emailContent.append(generateDetailComparisonTable(dbData, newData)); + + emailContent.append(""); + emailContent.append(""); return emailContent; } + + /** + * 生成明细对比表格 + * @param dbData 原数据 + * @param newData 新数据 + * @return 表格HTML + */ + private String generateDetailComparisonTable(List dbData, + List newData) { + StringBuilder table = new StringBuilder(); + + // 注意:不能用pn作为key,因为同一个pn可能有多行记录 + // 应该用itemNo进行一对一匹配,比较每一行的变化 + Map dbMap = dbData.stream() + .collect(Collectors.toMap(EcssCoDelNotifyDetail::getItemNo, detail -> detail, (v1, v2) -> v1)); + Map newMap = newData.stream() + .collect(Collectors.toMap(EcssCoDelNotifyDetail::getItemNo, detail -> detail, (v1, v2) -> v1)); + + // 获取所有itemNo + Set allItemNos = new HashSet<>(); + allItemNos.addAll(dbMap.keySet()); + allItemNos.addAll(newMap.keySet()); + List sortedItemNos = new ArrayList<>(allItemNos); + sortedItemNos.sort(Integer::compareTo); + + table.append(""); + table.append(""); + table.append(""); + table.append(""); + table.append(""); + table.append(""); + table.append(""); + table.append(""); + + for (Integer itemNo : sortedItemNos) { + EcssCoDelNotifyDetailData oldDetail = dbMap.get(itemNo); + EcssCoDelNotifyDetailData newDetail = newMap.get(itemNo); + + table.append(""); + table.append(""); + + // 判断变更类型 + if (oldDetail == null) { + // 新增行 + table.append(""); + table.append(""); + table.append(""); + table.append(""); + } else if (newDetail == null) { + // 删除行 + table.append(""); + table.append(""); + table.append(""); + table.append(""); + } else if (!oldDetail.getPn().equals(newDetail.getPn())) { + // 换料 + table.append(""); + table.append(""); + table.append(""); + table.append(""); + } else if (!oldDetail.getQty().equals(newDetail.getQty())) { + // 数量变化 + table.append(""); + table.append(""); + table.append(""); + table.append(""); + } else { + // 无变化 + table.append(""); + table.append(""); + table.append(""); + table.append(""); + } + + table.append(""); + } + + table.append("
    项次PN数量(原)数量(新)变更说明
    ").append(itemNo).append("").append(newDetail.getPn()).append("-").append(newDetail.getQty().setScale(0, RoundingMode.HALF_UP)).append("新增").append(oldDetail.getPn()).append("").append(oldDetail.getQty().setScale(0, RoundingMode.HALF_UP)).append("-已删除").append(oldDetail.getPn()).append(" → ").append(newDetail.getPn()).append("").append(oldDetail.getQty().setScale(0, RoundingMode.HALF_UP)).append("").append(newDetail.getQty().setScale(0, RoundingMode.HALF_UP)).append("换料").append(newDetail.getPn()).append("").append(oldDetail.getQty().setScale(0, RoundingMode.HALF_UP)).append("").append(newDetail.getQty().setScale(0, RoundingMode.HALF_UP)).append("数量变更").append(newDetail.getPn()).append("").append(oldDetail.getQty().setScale(0, RoundingMode.HALF_UP)).append("").append(newDetail.getQty().setScale(0, RoundingMode.HALF_UP)).append("-
    "); + return table.toString(); + } @Override public void updateEcssDel(EcssCoDelNotifyHeaderData data) { @@ -3721,11 +3798,12 @@ public class CoDelServiceImpl implements CoDelService { oldPalletDetailList, newPalletDetailList); // 获取发货通知单创建人邮箱 - String creatorEmail = coDelMapper.queryByUserName(notifyHeader.getCreateBy()).getEmail(); - if (StringUtils.isBlank(creatorEmail)) { - log.warn("发货通知单创建人{}没有配置邮箱地址", notifyHeader.getCreateBy()); + SysUserEntity creator = coDelMapper.queryByUserName(notifyHeader.getCreateBy()); + if (creator == null || StringUtils.isBlank(creator.getEmail())) { + log.warn("发货通知单创建人{}不存在或没有配置邮箱地址", notifyHeader.getCreateBy()); return; } + String creatorEmail = creator.getEmail(); // 发送邮件 String subject = String.format("发货通知单%s【发票:%s】一键装箱数据变更通知", @@ -4028,11 +4106,12 @@ public class CoDelServiceImpl implements CoDelService { String emailContent = generateBoxChangeEmailContent(notifyHeader, oldBoxList, newBoxList, operation, boxData); // 获取发货通知单创建人邮箱 - String creatorEmail = coDelMapper.queryByUserName(notifyHeader.getCreateBy()).getEmail(); - if (StringUtils.isBlank(creatorEmail)) { - log.warn("发货通知单创建人{}没有配置邮箱地址", notifyHeader.getCreateBy()); + SysUserEntity creator = coDelMapper.queryByUserName(notifyHeader.getCreateBy()); + if (creator == null || StringUtils.isBlank(creator.getEmail())) { + log.warn("发货通知单创建人{}不存在或没有配置邮箱地址", notifyHeader.getCreateBy()); return; } + String creatorEmail = creator.getEmail(); // 发送邮件 String subject = String.format("发货通知单%s【发票:%s】箱子%s通知", @@ -4078,11 +4157,12 @@ public class CoDelServiceImpl implements CoDelService { String emailContent = generateDetailChangeEmailContent(notifyHeader, oldPalletDetailList, newPalletDetailList, operation, detailData); // 获取发货通知单创建人邮箱 - String creatorEmail = coDelMapper.queryByUserName(notifyHeader.getCreateBy()).getEmail(); - if (StringUtils.isBlank(creatorEmail)) { - log.warn("发货通知单创建人{}没有配置邮箱地址", notifyHeader.getCreateBy()); + SysUserEntity creator = coDelMapper.queryByUserName(notifyHeader.getCreateBy()); + if (creator == null || StringUtils.isBlank(creator.getEmail())) { + log.warn("发货通知单创建人{}不存在或没有配置邮箱地址", notifyHeader.getCreateBy()); return; } + String creatorEmail = creator.getEmail(); // 发送邮件 String subject = String.format("发货通知单%s【发票:%s】箱明细%s通知",