Browse Source

催办

ecss-tx
han\hanst 1 month ago
parent
commit
836e9a0162
  1. 30
      src/main/java/com/xujie/sys/modules/erf/controller/ErfExpApplyController.java
  2. 10
      src/main/java/com/xujie/sys/modules/erf/service/ErfApprovalReminderService.java
  3. 335
      src/main/java/com/xujie/sys/modules/erf/service/impl/ErfApprovalReminderServiceImpl.java

30
src/main/java/com/xujie/sys/modules/erf/controller/ErfExpApplyController.java

@ -7,6 +7,7 @@ import com.xujie.sys.modules.erf.data.ErfFlowApprovalData;
import com.xujie.sys.modules.erf.data.ErfFlowStatusData; import com.xujie.sys.modules.erf.data.ErfFlowStatusData;
import com.xujie.sys.modules.erf.data.ErfPlannerScheduleData; import com.xujie.sys.modules.erf.data.ErfPlannerScheduleData;
import com.xujie.sys.modules.erf.entity.ErfFlowApproveLog; import com.xujie.sys.modules.erf.entity.ErfFlowApproveLog;
import com.xujie.sys.modules.erf.service.ErfApprovalReminderService;
import com.xujie.sys.modules.erf.service.ErfExpApplyService; import com.xujie.sys.modules.erf.service.ErfExpApplyService;
import com.xujie.sys.modules.erf.service.ErfFieldAuthService; import com.xujie.sys.modules.erf.service.ErfFieldAuthService;
import com.xujie.sys.modules.sys.controller.AbstractController; import com.xujie.sys.modules.sys.controller.AbstractController;
@ -35,6 +36,9 @@ public class ErfExpApplyController extends AbstractController {
@Autowired @Autowired
private ErfFieldAuthService erfFieldAuthService; private ErfFieldAuthService erfFieldAuthService;
@Autowired
private ErfApprovalReminderService erfApprovalReminderService;
/** /**
* 查询申请单列表 * 查询申请单列表
* *
@ -417,4 +421,30 @@ public class ErfExpApplyController extends AbstractController {
return R.error("录入失败: " + e.getMessage()); return R.error("录入失败: " + e.getMessage());
} }
} }
/**
* 手动催办向指定申请单所有未确认的审批人技术经理生产经理质量经理计划员发送催办邮件
*
* <p>不含三方确认人员</p>
*
* @param data 包含applyNo的请求数据
* @return 操作结果包含实际发送邮件人数
*/
@PostMapping("/urgeApproval")
@ResponseBody
public R urgeApproval(@RequestBody ErfExpApplyData data) {
try {
if (data.getApplyNo() == null || data.getApplyNo().trim().isEmpty()) {
return R.error("申请单号不能为空");
}
int sentCount = erfApprovalReminderService.sendManualUrgeEmail(data.getApplyNo().trim());
if (sentCount == 0) {
return R.ok("当前没有未确认的审批人,无需催办");
}
return R.ok(String.format("催办邮件已发送,共通知 %d 位审批人", sentCount));
} catch (Exception e) {
log.error("催办失败: " + e.getMessage(), e);
return R.error("催办失败: " + e.getMessage());
}
}
} }

10
src/main/java/com/xujie/sys/modules/erf/service/ErfApprovalReminderService.java

@ -35,4 +35,14 @@ public interface ErfApprovalReminderService {
* <p>提醒生产质量技术部门有待确认的工序</p> * <p>提醒生产质量技术部门有待确认的工序</p>
*/ */
void sendTriConfirmReminder(); void sendTriConfirmReminder();
/**
* 手动催办向指定申请单所有未确认的审批人发送催办邮件
*
* <p>催办范围技术经理生产经理质量经理计划员不含三方确认人员</p>
*
* @param applyNo 申请单号
* @return 实际发送催办邮件的人数
*/
int sendManualUrgeEmail(String applyNo);
} }

335
src/main/java/com/xujie/sys/modules/erf/service/impl/ErfApprovalReminderServiceImpl.java

@ -1,14 +1,18 @@
package com.xujie.sys.modules.erf.service.impl; package com.xujie.sys.modules.erf.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xujie.sys.common.utils.MailUtil; import com.xujie.sys.common.utils.MailUtil;
import com.xujie.sys.modules.erf.entity.ErfExpApply; import com.xujie.sys.modules.erf.entity.ErfExpApply;
import com.xujie.sys.modules.erf.entity.ErfExpTriConfirm; import com.xujie.sys.modules.erf.entity.ErfExpTriConfirm;
import com.xujie.sys.modules.erf.entity.ErfExpTriConfirmDetail; import com.xujie.sys.modules.erf.entity.ErfExpTriConfirmDetail;
import com.xujie.sys.modules.erf.entity.ErfFlowInstance;
import com.xujie.sys.modules.erf.entity.ErfFlowNodeInstance; import com.xujie.sys.modules.erf.entity.ErfFlowNodeInstance;
import com.xujie.sys.modules.erf.mapper.ErfExpApplyMapper; import com.xujie.sys.modules.erf.mapper.ErfExpApplyMapper;
import com.xujie.sys.modules.erf.mapper.ErfExpTriConfirmDetailMapper; import com.xujie.sys.modules.erf.mapper.ErfExpTriConfirmDetailMapper;
import com.xujie.sys.modules.erf.mapper.ErfExpTriConfirmMapper; import com.xujie.sys.modules.erf.mapper.ErfExpTriConfirmMapper;
import com.xujie.sys.modules.erf.mapper.ErfFlowInstanceMapper;
import com.xujie.sys.modules.erf.mapper.ErfFlowNodeInstanceMapper; import com.xujie.sys.modules.erf.mapper.ErfFlowNodeInstanceMapper;
import com.xujie.sys.modules.erf.service.ErfApprovalReminderService; import com.xujie.sys.modules.erf.service.ErfApprovalReminderService;
import com.xujie.sys.modules.pms.data.MailSendAddressData; import com.xujie.sys.modules.pms.data.MailSendAddressData;
@ -39,6 +43,9 @@ public class ErfApprovalReminderServiceImpl implements ErfApprovalReminderServic
@Autowired @Autowired
private ErfFlowNodeInstanceMapper erfFlowNodeInstanceMapper; private ErfFlowNodeInstanceMapper erfFlowNodeInstanceMapper;
@Autowired
private ErfFlowInstanceMapper erfFlowInstanceMapper;
@Autowired @Autowired
private ErfExpApplyMapper erfExpApplyMapper; private ErfExpApplyMapper erfExpApplyMapper;
@ -54,6 +61,11 @@ public class ErfApprovalReminderServiceImpl implements ErfApprovalReminderServic
@Autowired @Autowired
private ErfExpTriConfirmMapper erfExpTriConfirmMapper; private ErfExpTriConfirmMapper erfExpTriConfirmMapper;
private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
private static final String APPROVAL_PAGE_URL = "http://172.26.68.20:9001/#/erf-expApplyApproval";
private static final String PLANNER_PAGE_URL = "http://172.26.68.20:9001/#/erf-plannerSchedule";
@Value("${erf.reminder.manager.enabled:false}") @Value("${erf.reminder.manager.enabled:false}")
private boolean managerReminderEnabled; private boolean managerReminderEnabled;
@ -475,7 +487,7 @@ public class ErfApprovalReminderServiceImpl implements ErfApprovalReminderServic
emailBody.append("</tbody>"); emailBody.append("</tbody>");
emailBody.append("</table>"); emailBody.append("</table>");
emailBody.append("<br/>"); emailBody.append("<br/>");
emailBody.append("<a style='color:#0f84b0;' href='http://172.26.68.20:9001/#/erf-expApplyApproval'>前往查看</a>");
emailBody.append("<a style='color:#0f84b0;' href='").append(APPROVAL_PAGE_URL).append("'>前往查看</a>");
emailBody.append("<p style='color: #888;'>发送时间:").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("</p>"); emailBody.append("<p style='color: #888;'>发送时间:").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("</p>");
emailBody.append("</body></html>"); emailBody.append("</body></html>");
@ -548,7 +560,7 @@ public class ErfApprovalReminderServiceImpl implements ErfApprovalReminderServic
emailBody.append("</tbody>"); emailBody.append("</tbody>");
emailBody.append("</table>"); emailBody.append("</table>");
emailBody.append("<br/>"); emailBody.append("<br/>");
emailBody.append("<a style='color:#0f84b0;' href='http://172.26.68.20:9001/#/erf-plannerSchedule'>前往查看</a>");
emailBody.append("<a style='color:#0f84b0;' href='").append(PLANNER_PAGE_URL).append("'>前往查看</a>");
emailBody.append("<p style='color: #888;'>发送时间:").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("</p>"); emailBody.append("<p style='color: #888;'>发送时间:").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("</p>");
emailBody.append("</body></html>"); emailBody.append("</body></html>");
@ -639,7 +651,7 @@ public class ErfApprovalReminderServiceImpl implements ErfApprovalReminderServic
emailBody.append("</table>"); emailBody.append("</table>");
} }
emailBody.append("<a style='color:#0f84b0;' href='http://172.26.68.20:9001/#/erf-triConfirm'>前往查看</a>");
emailBody.append("<a style='color:#0f84b0;' href='http://172.26.68.20:9001/#/erf-triConfirm'>前往三方确认页面</a>");
emailBody.append("<p style='color: #888;'>发送时间:").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("</p>"); emailBody.append("<p style='color: #888;'>发送时间:").append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("</p>");
emailBody.append("</body></html>"); emailBody.append("</body></html>");
@ -708,6 +720,323 @@ public class ErfApprovalReminderServiceImpl implements ErfApprovalReminderServic
} }
} }
@Override
public int sendManualUrgeEmail(String applyNo) {
log.info("=== 开始手动催办 === 申请单: {}", applyNo);
// 1. 查询申请单基本信息
ErfExpApply apply = erfExpApplyMapper.selectOne(
new QueryWrapper<ErfExpApply>().eq("apply_no", applyNo));
if (apply == null) {
throw new RuntimeException("申请单不存在: " + applyNo);
}
// 2. 查询流程实例从remark字段解析出下达时指定的全量审批人
// 节点实例是逐步创建的如计划员节点在经理审批完成后才创建
// 因此必须从流程实例的remark中读取全量审批人而非仅查当前"待审核"节点
ErfFlowInstance flowInstance = erfFlowInstanceMapper.selectOne(
new QueryWrapper<ErfFlowInstance>().eq("apply_no", applyNo));
if (flowInstance == null) {
throw new RuntimeException("申请单 " + applyNo + " 尚未提交审批流程");
}
String approverJson = flowInstance.getRemark();
if (approverJson == null || approverJson.trim().isEmpty()) {
throw new RuntimeException("申请单 " + applyNo + " 流程实例中没有审批人信息");
}
// 3. 解析JSON获取全量审批人ID列表
long techManagerId;
List<Long> prodManagerIds;
List<Long> qualityManagerIds;
List<Long> plannerIds;
try {
JsonNode root = JSON_MAPPER.readTree(approverJson);
techManagerId = root.path("techManagerId").asLong(0);
prodManagerIds = new ArrayList<>();
root.path("prodManagerIds").forEach(n -> prodManagerIds.add(n.asLong()));
qualityManagerIds = new ArrayList<>();
root.path("qualityManagerIds").forEach(n -> qualityManagerIds.add(n.asLong()));
plannerIds = new ArrayList<>();
root.path("plannerIds").forEach(n -> plannerIds.add(n.asLong()));
} catch (Exception e) {
throw new RuntimeException("解析审批人JSON失败: " + e.getMessage(), e);
}
log.info("申请单 {} 全量审批人 - 技术经理: {}, 生产经理: {}, 质量经理: {}, 计划员: {}",
applyNo, techManagerId, prodManagerIds, qualityManagerIds, plannerIds);
// 4. 查询该申请单已存在的节点实例判断谁已完成
// "已批准""已完成"表示该人已经处理完毕无需再催
List<ErfFlowNodeInstance> existingNodes = erfFlowNodeInstanceMapper.selectList(
new QueryWrapper<ErfFlowNodeInstance>()
.eq("apply_no", applyNo)
.in("node_code", "技术经理审批", "生产经理审批", "质量经理审批", "计划员排产"));
Set<Long> completedTechManagers = new HashSet<>();
Set<Long> completedProdManagers = new HashSet<>();
Set<Long> completedQualityManagers = new HashSet<>();
Set<Long> completedPlanners = new HashSet<>();
for (ErfFlowNodeInstance node : existingNodes) {
if (node.getAssigneeUserId() == null) continue;
boolean done = "已批准".equals(node.getStatus()) || "已完成".equals(node.getStatus());
if (!done) continue;
switch (node.getNodeCode()) {
case "技术经理审批": completedTechManagers.add(node.getAssigneeUserId()); break;
case "生产经理审批": completedProdManagers.add(node.getAssigneeUserId()); break;
case "质量经理审批": completedQualityManagers.add(node.getAssigneeUserId()); break;
case "计划员排产": completedPlanners.add(node.getAssigneeUserId()); break;
default: break;
}
}
// 5. 查询当前实际"待审核"的节点构建"userId -> 当前活跃节点编码集合"映射
// 必须按角色节点编码判断而非仅凭userId否则同一人担任多个角色时会误判
// 某人同时是技术经理和计划员技术经理节点"待审核"
// 若只用userId判断其计划员催办邮件也会显示"当前正等待您处理"实际尚未轮到
String currentNodeCode = flowInstance.getCurrentNodeCode();
List<ErfFlowNodeInstance> activeNodes = existingNodes.stream()
.filter(n -> "待审核".equals(n.getStatus()))
.collect(Collectors.toList());
// 当前待处理人姓名用于告知非当前步骤的收件人
String currentPendingNames = activeNodes.stream()
.filter(n -> n.getAssigneeName() != null)
.map(ErfFlowNodeInstance::getAssigneeName)
.distinct()
.collect(Collectors.joining("、"));
// userId -> 该用户当前"待审核"的节点编码集合精确到角色
Map<Long, Set<String>> activeNodesByUser = new HashMap<>();
for (ErfFlowNodeInstance node : activeNodes) {
if (node.getAssigneeUserId() != null) {
activeNodesByUser
.computeIfAbsent(node.getAssigneeUserId(), k -> new HashSet<>())
.add(node.getNodeCode());
}
}
log.info("申请单 {} 当前节点: {}, 当前待处理人: {}", applyNo, currentNodeCode, currentPendingNames);
// 6. 按角色分别判断 isCurrentStep再发送催办邮件
// isCurrentStep = 该人在该角色对应的节点上有"待审核"记录
int sentCount = 0;
// 技术经理
if (techManagerId != 0 && !completedTechManagers.contains(techManagerId)) {
boolean isCurrent = activeNodesByUser
.getOrDefault(techManagerId, Collections.emptySet())
.contains("技术经理审批");
if (sendManagerUrgeEmail(apply, techManagerId, currentNodeCode, currentPendingNames, isCurrent)) {
sentCount++;
}
}
// 生产经理
for (Long id : prodManagerIds) {
if (!completedProdManagers.contains(id)) {
boolean isCurrent = activeNodesByUser
.getOrDefault(id, Collections.emptySet())
.contains("生产经理审批");
if (sendManagerUrgeEmail(apply, id, currentNodeCode, currentPendingNames, isCurrent)) {
sentCount++;
}
}
}
// 质量经理
for (Long id : qualityManagerIds) {
if (!completedQualityManagers.contains(id)) {
boolean isCurrent = activeNodesByUser
.getOrDefault(id, Collections.emptySet())
.contains("质量经理审批");
if (sendManagerUrgeEmail(apply, id, currentNodeCode, currentPendingNames, isCurrent)) {
sentCount++;
}
}
}
// 计划员
for (Long id : plannerIds) {
if (!completedPlanners.contains(id)) {
boolean isCurrent = activeNodesByUser
.getOrDefault(id, Collections.emptySet())
.contains("计划员排产");
if (sendPlannerUrgeEmail(apply, id, currentNodeCode, currentPendingNames, isCurrent)) {
sentCount++;
}
}
}
log.info("=== 手动催办完成 === 申请单: {}, 成功发送邮件人数: {}", applyNo, sentCount);
return sentCount;
}
/**
* 向经理技术/生产/质量发送催办邮件链接指向审批待办页
*
* @param apply 申请单信息
* @param managerId 收件经理用户ID
* @param currentNodeCode 当前流程节点编码
* @param currentPendingNames 当前待处理人姓名逗号分隔
* @param isCurrentStep 该经理是否就是当前步骤的待处理人
*/
private boolean sendManagerUrgeEmail(ErfExpApply apply, Long managerId,
String currentNodeCode, String currentPendingNames,
boolean isCurrentStep) {
try {
UserEmailInfoDto manager = sysUserDao.getUserEmailInfoById(managerId);
if (manager == null) {
log.warn("经理ID {} 不存在,跳过催办邮件", managerId);
return false;
}
if (manager.getEmail() == null || manager.getEmail().trim().isEmpty()) {
log.warn("经理 {} 未配置邮箱,跳过催办邮件", manager.getUsername());
return false;
}
String submitTimeStr = formatDate(apply.getSubmitTime());
String subject = String.format("【催办提醒】申请单 %s 等待您审批确认", apply.getApplyNo());
StringBuilder body = new StringBuilder();
body.append("<html><body style='font-family:Arial,sans-serif;color:#333;'>");
body.append("<h3 style='color:#E6A23C;'>&#9888; 审批催办提醒</h3>");
body.append("<p>尊敬的 <b>").append(manager.getUsername()).append("</b>,您好!</p>");
if (isCurrentStep) {
// 当前步骤就是该经理需要立即处理
body.append("<p style='color:#F56C6C;font-weight:bold;'>&#128680; 当前正等待您完成审批,请尽快处理!</p>");
} else {
// 非当前步骤告知当前进度
body.append("<p>本申请单已向您发出催办,您的审批步骤尚未到达。</p>");
body.append(buildCurrentStepBlock(currentNodeCode, currentPendingNames));
}
body.append("<hr style='border:1px solid #EBEEF5;'/>");
body.append(buildApplyInfoTable(apply, submitTimeStr));
body.append("<p>请点击以下链接前往审批:</p>");
body.append("<p><a style='color:#0f84b0;font-size:14px;' href='").append(APPROVAL_PAGE_URL)
.append("'>前往审批待办页面</a></p>");
body.append(buildFooter());
body.append("</body></html>");
sendMail(subject, body.toString(), new String[]{manager.getEmail()}, "手动催办-经理");
log.info("已向经理 {} ({}) 发送催办邮件,是否当前步骤: {}", manager.getUsername(), manager.getEmail(), isCurrentStep);
return true;
} catch (Exception e) {
log.error("向经理ID {} 发送催办邮件失败: {}", managerId, e.getMessage(), e);
return false;
}
}
/**
* 向计划员发送催办邮件链接指向计划员排产页
*
* @param apply 申请单信息
* @param plannerId 收件计划员用户ID
* @param currentNodeCode 当前流程节点编码
* @param currentPendingNames 当前待处理人姓名逗号分隔
* @param isCurrentStep 该计划员是否就是当前步骤的待处理人
*/
private boolean sendPlannerUrgeEmail(ErfExpApply apply, Long plannerId,
String currentNodeCode, String currentPendingNames,
boolean isCurrentStep) {
try {
UserEmailInfoDto planner = sysUserDao.getUserEmailInfoById(plannerId);
if (planner == null) {
log.warn("计划员ID {} 不存在,跳过催办邮件", plannerId);
return false;
}
if (planner.getEmail() == null || planner.getEmail().trim().isEmpty()) {
log.warn("计划员 {} 未配置邮箱,跳过催办邮件", planner.getUsername());
return false;
}
String submitTimeStr = formatDate(apply.getSubmitTime());
String subject = String.format("【催办提醒】申请单 %s 等待您安排排产", apply.getApplyNo());
StringBuilder body = new StringBuilder();
body.append("<html><body style='font-family:Arial,sans-serif;color:#333;'>");
body.append("<h3 style='color:#E6A23C;'>&#9888; 排产催办提醒</h3>");
body.append("<p>尊敬的 <b>").append(planner.getUsername()).append("</b> 计划员,您好!</p>");
if (isCurrentStep) {
body.append("<p style='color:#F56C6C;font-weight:bold;'>&#128680; 当前正等待您安排排产,请尽快处理!</p>");
} else {
body.append("<p>本申请单已向您发出催办,排产步骤尚未到达(需经理审批完成后方可排产)。</p>");
body.append(buildCurrentStepBlock(currentNodeCode, currentPendingNames));
}
body.append("<hr style='border:1px solid #EBEEF5;'/>");
body.append(buildApplyInfoTable(apply, submitTimeStr));
body.append("<p>请点击以下链接前往排产:</p>");
body.append("<p><a style='color:#0f84b0;font-size:14px;' href='").append(PLANNER_PAGE_URL)
.append("'>前往计划员排产页面</a></p>");
body.append(buildFooter());
body.append("</body></html>");
sendMail(subject, body.toString(), new String[]{planner.getEmail()}, "手动催办-计划员");
log.info("已向计划员 {} ({}) 发送催办邮件,是否当前步骤: {}", planner.getUsername(), planner.getEmail(), isCurrentStep);
return true;
} catch (Exception e) {
log.error("向计划员ID {} 发送催办邮件失败: {}", plannerId, e.getMessage(), e);
return false;
}
}
/**
* 构建"当前流程进度"提示块用于非当前步骤收件人
*/
private String buildCurrentStepBlock(String currentNodeCode, String currentPendingNames) {
if (currentNodeCode == null || currentNodeCode.isEmpty()) {
return "";
}
String pendingPart = (currentPendingNames != null && !currentPendingNames.isEmpty())
? ",待处理人:<b>" + currentPendingNames + "</b>"
: "";
return "<div style='margin:12px 0;padding:10px 14px;"
+ "background:#FFF9F0;border-left:4px solid #E6A23C;border-radius:3px;'>"
+ "<span style='color:#E6A23C;font-weight:bold;'>&#128336; 当前流程进度</span><br/>"
+ "正在进行:<b>" + currentNodeCode + "</b>" + pendingPart
+ "</div>";
}
/**
* 构建申请单信息HTML表格
*/
private String buildApplyInfoTable(ErfExpApply apply, String submitTimeStr) {
return "<table border='1' cellpadding='8' cellspacing='0' style='border-collapse:collapse;width:100%;margin-bottom:16px;'>"
+ "<thead style='background-color:#FDF6EC;'><tr>"
+ "<th align='center'>申请单号</th>"
+ "<th align='center'>事业部</th>"
+ "<th align='center'>试验名称</th>"
+ "<th align='center'>试验类型</th>"
+ "<th align='center'>申请人</th>"
+ "<th align='center'>下达时间</th>"
+ "</tr></thead><tbody><tr>"
+ "<td align='center'><b>" + apply.getApplyNo() + "</b></td>"
+ "<td align='center'>" + nvl(apply.getBuNo()) + "</td>"
+ "<td>" + nvl(apply.getTitle()) + "</td>"
+ "<td align='center'>" + nvl(apply.getExperimentType()) + "</td>"
+ "<td align='center'>" + nvl(apply.getCreatorName()) + "</td>"
+ "<td align='center'>" + submitTimeStr + "</td>"
+ "</tr></tbody></table>";
}
private String buildFooter() {
return "<p style='color:#888;font-size:12px;'>发送时间:"
+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
+ "</p>";
}
private String formatDate(Date date) {
if (date == null) return "";
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
.format(date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime());
}
private String nvl(String s) {
return s != null ? s : "";
}
private void sendMail(String subject, String body, String[] toEmails, String mailType) { private void sendMail(String subject, String body, String[] toEmails, String mailType) {
try { try {
MailSendAddressData mailSendData = qcMapper.getSendMailFromAddress(); MailSendAddressData mailSendData = qcMapper.getSendMailFromAddress();

Loading…
Cancel
Save