Browse Source

在三位经理全部审批通过并进入计划员排产节点时,向计划员发送与下达时相同的邮件,并向试验负责人发送审批通过通知

ecss-tx
han\hanst 3 weeks ago
parent
commit
2f4dc81697
  1. 2
      src/main/java/com/xujie/sys/modules/erf/service/impl/ErfApprovalReminderServiceImpl.java
  2. 143
      src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpApplyServiceImpl.java

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

@ -560,7 +560,7 @@ public class ErfApprovalReminderServiceImpl implements ErfApprovalReminderServic
emailBody.append("<td>").append(apply.getQuantityReq() != null ? apply.getQuantityReq() : "").append("</td>");
emailBody.append("<td>").append(apply.getRemark() != null ? apply.getRemark() : "").append("</td>");
emailBody.append("<td>").append(expectedFinishDateStr).append("</td>");
emailBody.append("<td>").append(apply.getCreatorName() != null ? apply.getCreatorName() : "").append("</td>");
emailBody.append("<td>").append(apply.getProjectLeader()!= null ? apply.getProjectLeader() : "").append("</td>");
emailBody.append("</tr>");
}

143
src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpApplyServiceImpl.java

@ -26,6 +26,7 @@ import com.xujie.sys.modules.erf.service.ErfTriConfirmService;
import com.xujie.sys.modules.sys.dao.SysUserDao;
import com.xujie.sys.modules.sys.dto.ManagerInfoDto;
import com.xujie.sys.modules.sys.dto.UserRoleDto;
import com.xujie.sys.modules.sys.entity.SysUserEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
@ -38,6 +39,8 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.xujie.sys.common.utils.ShiroUtils.getUserId;
@ -281,9 +284,22 @@ public class ErfExpApplyServiceImpl extends ServiceImpl<ErfExpApplyMapper, ErfEx
if (needWaitForOtherApprovals(data.getApplyNo(), data.getNodeCode())) {
log.info("当前节点还有其他审批人未完成,暂不流转");
} else {
// 所有并发审批都完成流转到下一节点
// 所有并发审批都完成流转到下一节点经理全部通过后下一节点为计划员排产
String nextNodeCode = erfFlowEngineService.getNextNodeCode(data.getApplyNo(), data.getNodeCode());
erfFlowEngineService.moveToNextNode(data.getApplyNo(), data.getNodeCode(), data);
log.info("所有审批完成,流转到下一节点");
if ("计划员排产".equals(nextNodeCode)) {
ErfExpApply approvedEntity = this.getById(data.getApplyNo());
if (approvedEntity != null) {
List<Long> plannerUserIds = extractPlannerIdsFromFlowRemark(data.getApplyNo());
if (!plannerUserIds.isEmpty()) {
sendPlannerSubmitNotification(approvedEntity, plannerUserIds);
} else {
log.warn("流程 remark 中未解析到计划员ID,跳过计划员邮件: {}", data.getApplyNo());
}
sendProjectLeaderApprovalPassedNotification(approvedEntity);
}
}
}
} else if ("驳回".equals(data.getAction())) {
// 驳回返回到指定节点或创建人
@ -1312,6 +1328,49 @@ public class ErfExpApplyServiceImpl extends ServiceImpl<ErfExpApplyMapper, ErfEx
return true;
}
/**
* 从流程实例 remarkJSON中解析下达时保存的计划员用户ID列表与流程引擎 {@code extractPlannerIds} 逻辑一致
*/
private List<Long> extractPlannerIdsFromFlowRemark(String applyNo) {
QueryWrapper<ErfFlowInstance> flowQuery = new QueryWrapper<>();
flowQuery.eq("apply_no", applyNo);
ErfFlowInstance flowInstance = erfFlowInstanceMapper.selectOne(flowQuery);
if (flowInstance == null || flowInstance.getRemark() == null || flowInstance.getRemark().isEmpty()) {
return Collections.emptyList();
}
String json = flowInstance.getRemark();
try {
Pattern p = Pattern.compile("\"plannerIds\":\\[([0-9,]+)\\]");
Matcher m = p.matcher(json);
if (m.find()) {
String idsStr = m.group(1);
return Arrays.stream(idsStr.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.map(Long::valueOf)
.filter(id -> id > 0)
.collect(Collectors.toList());
}
int idx = json.indexOf("\"plannerId\":");
if (idx >= 0) {
String sub = json.substring(idx + 12).trim();
int end = sub.indexOf(',');
if (end < 0) {
end = sub.indexOf('}');
}
if (end > 0) {
long id = Long.parseLong(sub.substring(0, end).trim());
if (id > 0) {
return Collections.singletonList(id);
}
}
}
} catch (Exception e) {
log.error("解析流程实例中的计划员ID失败 applyNo={}: {}", applyNo, e.getMessage());
}
return Collections.emptyList();
}
@Override
public void cancelExpApply(String applyNo, Long userId) {
log.info("=== 开始取消试验单 === 试验单号: {}, 操作人: {}", applyNo, userId);
@ -1531,6 +1590,86 @@ public class ErfExpApplyServiceImpl extends ServiceImpl<ErfExpApplyMapper, ErfEx
}
}
/**
* 经理层审批全部通过后进入计划员排产节点时通知试验负责人其负责的试验申请单已审批通过
*/
private void sendProjectLeaderApprovalPassedNotification(ErfExpApply entity) {
try {
UserEmailInfoDto leader = resolveProjectLeaderEmailInfo(entity);
if (leader == null) {
log.warn("无法解析试验负责人邮箱,跳过审批通过通知: applyNo={}", entity.getApplyNo());
return;
}
String email = leader.getEmail();
if (email == null || email.trim().isEmpty()) {
log.warn("试验负责人 {} 未配置邮箱,跳过审批通过通知", leader.getUsername());
return;
}
MailSendAddressData mailSendData = qcMapper.getSendMailFromAddress();
if (mailSendData == null) {
log.error("邮件发送配置未设置,无法发送试验负责人审批通过通知");
return;
}
String todayStr = DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now());
String expectedFinishDateStr = entity.getExpectedFinishDate() != null
? DateTimeFormatter.ofPattern("yyyy-MM-dd")
.format(entity.getExpectedFinishDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime())
: todayStr;
String subject = String.format("【工程实验申请审批通过】%s - %s",
entity.getApplyNo(), entity.getTitle() != null ? entity.getTitle() : "");
String tableBody = buildPlannerNotificationTable(entity, todayStr, expectedFinishDateStr);
String body = "<html><body>"
+ "<h3>尊敬的 " + leader.getUsername() + ":</h3>"
+ "<p>您好!您作为试验负责人负责的工程实验试验单,经理层审批已全部通过,流程已进入<strong>计划员排产</strong>环节。</p>"
+ "<p>请留意后续排产与执行安排。</p>"
+ "<hr/>" + tableBody
+ "<br/><p style='color:#888;'>发送时间:"
+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
+ "</p></body></html>";
MailUtil.sendMail(subject, body, new String[]{email}, mailSendData);
log.info("已向试验负责人 {} ({}) 发送审批通过通知,试验单: {}",
leader.getUsername(), email, entity.getApplyNo());
SendMailRecord mailRecord = new SendMailRecord();
mailRecord.setType("工程实验申请试验负责人审批通过通知");
mailRecord.setDocumentNo(entity.getApplyNo());
mailRecord.setRecipient(email);
mailRecord.setSendDate(new Date());
qcMapper.saveSendMailRecord(mailRecord);
} catch (Exception e) {
log.error("发送试验负责人审批通过邮件失败,试验单: {}, 错误: {}", entity.getApplyNo(), e.getMessage(), e);
}
}
/**
* 根据试验单上的试验负责人字段解析系统用户邮箱优先用户名其次用户显示名精确匹配
*/
private UserEmailInfoDto resolveProjectLeaderEmailInfo(ErfExpApply entity) {
if (entity == null) {
return null;
}
if (StringUtils.isNotBlank(entity.getProjectLeaderName())) {
SysUserEntity u = sysUserDao.queryByUserName(entity.getProjectLeaderName());
if (u != null) {
return sysUserDao.getUserEmailInfoById(u.getUserId());
}
}
if (StringUtils.isNotBlank(entity.getProjectLeader())) {
SysUserEntity u = sysUserDao.selectOne(new QueryWrapper<SysUserEntity>()
.eq("user_display", entity.getProjectLeader())
.last("OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY"));
if (u != null) {
return sysUserDao.getUserEmailInfoById(u.getUserId());
}
}
return null;
}
/**
* 排产完成后向仓库角色用户发送邮件通知
* 邮件内容包含试验单信息表格和原材料清单
@ -1653,7 +1792,7 @@ public class ErfExpApplyServiceImpl extends ServiceImpl<ErfExpApplyMapper, ErfEx
+ "<td>" + (entity.getQuantityReq() != null ? entity.getQuantityReq() : "") + "</td>"
+ "<td>" + (entity.getRemark() != null ? entity.getRemark() : "") + "</td>"
+ "<td>" + expectedFinishDateStr + "</td>"
+ "<td>" + (entity.getCreatorName() != null ? entity.getCreatorName() : "") + "</td>"
+ "<td>" + (entity.getProjectLeader() != null ? entity.getProjectLeader() : "") + "</td>"
+ "</tr></tbody></table>";
}

Loading…
Cancel
Save