From 620bb4712a31791231c4381581f0f60088f079fe Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 27 五月 2026 14:03:45 +0800
Subject: [PATCH] Merge branch 'refs/heads/dev_New_pro' into dev_宁夏_英泽防锈
---
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java | 753 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 753 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
new file mode 100644
index 0000000..2a4f52a
--- /dev/null
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
@@ -0,0 +1,753 @@
+package com.ruoyi.approve.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
+import com.ruoyi.approve.bean.vo.ApprovalInstanceVo;
+import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
+import com.ruoyi.approve.mapper.ApprovalTemplateNodeApproverMapper;
+import com.ruoyi.approve.mapper.FinReimbursementMapper;
+import com.ruoyi.approve.pojo.*;
+import com.ruoyi.approve.service.*;
+import com.ruoyi.approve.utils.ApproveProcessConfigNodeUtils;
+import com.ruoyi.basic.enums.ApplicationTypeEnum;
+import com.ruoyi.basic.enums.RecordTypeEnum;
+import com.ruoyi.basic.utils.FileUtil;
+import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsMapper;
+import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeDeptMapper;
+import com.ruoyi.collaborativeApproval.mapper.EnterpriseNewsScopeUserMapper;
+import com.ruoyi.collaborativeApproval.pojo.EnterpriseNews;
+import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeDept;
+import com.ruoyi.collaborativeApproval.pojo.EnterpriseNewsScopeUser;
+import com.ruoyi.common.enums.*;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.OrderUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.web.domain.R;
+import com.ruoyi.procurementrecord.utils.StockUtils;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.mapper.SysDeptMapper;
+import com.ruoyi.project.system.mapper.SysUserDeptMapper;
+import com.ruoyi.project.system.mapper.SysUserMapper;
+import com.ruoyi.project.system.service.ISysNoticeService;
+import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
+import com.ruoyi.purchase.pojo.PurchaseLedger;
+import com.ruoyi.quality.utils.QualityInspectHelper;
+import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
+import com.ruoyi.sales.mapper.SalesQuotationMapper;
+import com.ruoyi.sales.mapper.ShippingInfoMapper;
+import com.ruoyi.sales.pojo.SalesLedgerProduct;
+import com.ruoyi.sales.pojo.SalesQuotation;
+import com.ruoyi.sales.pojo.ShippingInfo;
+import com.ruoyi.staff.mapper.HolidayApplicationMapper;
+import com.ruoyi.staff.pojo.HolidayApplication;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 瀹℃壒瀹炰緥鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @since 2026-05-18 03:27:46
+ */
+@Service
+@RequiredArgsConstructor
+public class ApprovalInstanceServiceImpl extends ServiceImpl<ApprovalInstanceMapper, ApprovalInstance> implements ApprovalInstanceService {
+
+ private static final String ENTERPRISE_NEWS_STATUS_PUBLISHED = "PUBLISHED";
+ private static final String ENTERPRISE_NEWS_STATUS_REJECTED = "REJECTED";
+
+ private final ApprovalInstanceMapper approvalInstanceMapper;
+ private final ApproveProcessConfigNodeUtils approveProcessConfigNodeUtils;
+ private final ApprovalInstanceNodeService approvalInstanceNodeService;
+ private final ApprovalTaskService approvalTaskService;
+ private final ApprovalRecordService approvalRecordService;
+ private final ApprovalTemplateNodeService approvalTemplateNodeService;
+ private final FinReimbursementMapper finReimbursementMapper;
+ private final FileUtil fileUtil;
+ private final ISysNoticeService sysNoticeService;
+ private final PurchaseLedgerMapper purchaseLedgerMapper;
+ private final SalesLedgerProductMapper salesLedgerProductMapper;
+ private final StockUtils stockUtils;
+ private final SalesQuotationMapper salesQuotationMapper;
+ private final ShippingInfoMapper shippingInfoMapper;
+ private final QualityInspectHelper qualityInspectHelper;
+ private final EnterpriseNewsScopeUserMapper enterpriseNewsScopeUserMapper;
+ private final SysUserMapper sysUserMapper;
+ private final SysUserDeptMapper sysUserDeptMapper;
+ private final SysDeptMapper sysDeptMapper;
+ private final HolidayApplicationMapper holidayApplicationMapper;
+ private final EnterpriseNewsMapper enterpriseNewsMapper;
+ private final EnterpriseNewsScopeDeptMapper enterpriseNewsScopeDeptMapper;
+ private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper;
+
+ @Override
+ public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
+ IPage<ApprovalInstanceVo> approvalInstanceVoIPage = approvalInstanceMapper.listPage(page, approvalInstanceDto);
+
+ List<ApprovalInstanceVo> records = approvalInstanceVoIPage.getRecords();
+ if (records == null || records.isEmpty()) {
+ return R.ok(approvalInstanceVoIPage);
+ }
+ records.forEach(vo -> {
+ vo.setBusinessName(TypeEnums.getLabelByValue(vo.getBusinessType()));
+ });
+ Long currentUserId = SecurityUtils.getUserId();
+
+ List<Long> instanceIds = records.stream()
+ .map(ApprovalInstanceVo::getId)
+ .filter(id -> id != null)
+ .distinct()
+ .collect(Collectors.toList());
+
+ if (!instanceIds.isEmpty()) {
+ Map<Long, List<ApprovalRecord>> recordMap = approvalRecordService.list(
+ Wrappers.<ApprovalRecord>lambdaQuery()
+ .in(ApprovalRecord::getInstanceId, instanceIds)
+ .eq(ApprovalRecord::getDeleted, 0)
+ ).stream().collect(Collectors.groupingBy(ApprovalRecord::getInstanceId));
+ Map<Long, List<ApprovalTask>> taskMap = approvalTaskService.list(
+ Wrappers.<ApprovalTask>lambdaQuery()
+ .in(ApprovalTask::getInstanceId, instanceIds)
+ .eq(ApprovalTask::getDeleted, 0)
+ ).stream().collect(Collectors.groupingBy(ApprovalTask::getInstanceId));
+
+ for (ApprovalInstanceVo vo : records) {
+ vo.setIsApprove(approveProcessConfigNodeUtils.isCurrentApprover(vo.getId(), currentUserId));
+ vo.setRecords(recordMap.getOrDefault(vo.getId(), new ArrayList<>()));
+ vo.setTasks(taskMap.getOrDefault(vo.getId(), new ArrayList<>()));
+ vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.APPROVAL_INSTANCE, vo.getId()));
+ }
+
+ }
+ return R.ok(approvalInstanceVoIPage);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean add(ApprovalInstanceDto approvalInstanceDto) {
+ String instanceNo = OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no", approvalInstanceDto.getCreateTime() != null ? approvalInstanceDto.getCreateTime() : LocalDateTime.now());
+ approvalInstanceDto.setInstanceNo(instanceNo);
+ approvalInstanceDto.setStatus("PENDING");
+ approvalInstanceDto.setCurrentLevel(1);
+ boolean saved = this.save(approvalInstanceDto);
+ if (!saved) {
+ return false;
+ }
+ approveProcessConfigNodeUtils.createCurrentNodeAndTasks(approvalInstanceDto);
+ fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs());
+ sendApproveNotice(approvalInstanceDto, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
+ return true;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean update(ApprovalInstanceDto approvalInstanceDto) {
+ if (approvalInstanceDto == null || approvalInstanceDto.getId() == null) {
+ return false;
+ }
+ // 鍒ゆ柇鏄惁鏈夋鍦ㄨ繘琛岀殑瀹℃壒浠诲姟锛屾湁鍒欎笉鍏佽淇敼
+ long pendingTaskCount = approvalTaskService.count(
+ Wrappers.<ApprovalTask>lambdaQuery()
+ .eq(ApprovalTask::getInstanceId, approvalInstanceDto.getId())
+ .eq(ApprovalTask::getTaskStatus, "PENDING")
+ .eq(ApprovalTask::getDeleted, 0)
+ );
+ if (pendingTaskCount > 0) {
+ throw new ServiceException("璇ュ鎵瑰崟鏈夋鍦ㄨ繘琛岀殑瀹℃壒浠诲姟锛屼笉鍏佽淇敼");
+ }
+ boolean updated = this.updateById(approvalInstanceDto);
+ if (!updated) {
+ return false;
+ }
+ fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, approvalInstanceDto.getId(), approvalInstanceDto.getStorageBlobDTOs());
+ return true;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean delete(List<Long> ids) {
+ if (ids == null || ids.isEmpty()) {
+ return false;
+ }
+ fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, ids);
+
+ int instanceRows = approvalInstanceMapper.update(
+ null,
+ Wrappers.<ApprovalInstance>lambdaUpdate()
+ .in(ApprovalInstance::getId, ids)
+ .eq(ApprovalInstance::getDeleted, 0)
+ .set(ApprovalInstance::getDeleted, (byte) 1)
+ );
+
+ LambdaUpdateWrapper<ApprovalInstanceNode> nodeUpdateWrapper = Wrappers.lambdaUpdate();
+ nodeUpdateWrapper.in(ApprovalInstanceNode::getInstanceId, ids)
+ .eq(ApprovalInstanceNode::getDeleted, 0)
+ .set(ApprovalInstanceNode::getDeleted, (byte) 1);
+ approvalInstanceNodeService.update(nodeUpdateWrapper);
+
+ LambdaUpdateWrapper<ApprovalTask> taskUpdateWrapper = Wrappers.lambdaUpdate();
+ taskUpdateWrapper.in(ApprovalTask::getInstanceId, ids)
+ .eq(ApprovalTask::getDeleted, 0)
+ .set(ApprovalTask::getDeleted, (byte) 1);
+ approvalTaskService.update(taskUpdateWrapper);
+
+ LambdaUpdateWrapper<ApprovalRecord> recordUpdateWrapper = Wrappers.lambdaUpdate();
+ recordUpdateWrapper.in(ApprovalRecord::getInstanceId, ids)
+ .eq(ApprovalRecord::getDeleted, 0)
+ .set(ApprovalRecord::getDeleted, (byte) 1);
+ approvalRecordService.update(recordUpdateWrapper);
+
+ return instanceRows > 0;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public R approve(ApprovalInstanceDto approvalInstanceDto) {
+ if (approvalInstanceDto == null || approvalInstanceDto.getId() == null) {
+ return R.fail("瀹℃壒瀹炰緥 ID 涓嶈兘涓虹┖");
+ }
+ String approveAction = normalizeApproveAction(approvalInstanceDto.getApproveAction());
+ if (approveAction == null) {
+ return R.fail("瀹℃壒鍔ㄤ綔鍙敮鎸� APPROVED 鎴� REJECTED");
+ }
+
+ ApprovalInstance instance = getPendingApprovalInstance(approvalInstanceDto.getId());
+ if (instance == null) {
+ return R.fail("瀹℃壒瀹炰緥涓嶅瓨鍦�");
+ }
+
+ ApprovalInstanceNode currentNode = approveProcessConfigNodeUtils.getCurrentNode(instance.getId());
+ if (currentNode == null) {
+ return R.fail("褰撳墠娌℃湁寰呭鐞嗙殑瀹℃壒鑺傜偣");
+ }
+
+ Long currentUserId = SecurityUtils.getUserId();
+ ApprovalTask currentTask = approveProcessConfigNodeUtils.getCurrentUserTask(instance.getId(), currentUserId);
+ if (currentTask == null) {
+ return R.fail("褰撳墠鐢ㄦ埛娌℃湁鍙鎵逛换鍔�");
+ }
+
+ LoginUser loginUser = SecurityUtils.getLoginUser();
+ String operatorName = loginUser.getUser() != null ? loginUser.getUser().getNickName() : SecurityUtils.getUsername();
+ LocalDateTime now = LocalDateTime.now();
+
+ if (!updateCurrentTask(approvalInstanceDto, approveAction, currentTask, now)) {
+ return R.fail("褰撳墠浠诲姟宸茶澶勭悊锛岃鍒锋柊鍚庨噸璇�");
+ }
+
+ saveApprovalRecord(
+ instance.getId(),
+ currentNode.getId(),
+ currentTask.getId(),
+ currentUserId,
+ operatorName,
+ approveAction,
+ approvalInstanceDto.getApproveComment()
+ );
+ //瀹℃壒鎷掔粷鐨勫鐞�
+ if ("REJECTED".equals(approveAction)) {
+ return rejectCurrentNode(instance, currentNode, now);
+ }
+ if (!approveProcessConfigNodeUtils.canProceedToNextLevel(instance.getId(), currentNode.getApproveType())) {
+ return R.ok("瀹℃壒鎴愬姛锛岀瓑寰呭叾浠栧鎵逛汉澶勭悊");
+ }
+
+ return approveAndMoveNext(instance, currentNode, approvalInstanceDto, now);
+ }
+
+ private String normalizeApproveAction(String approveAction) {
+ if (!StringUtils.hasText(approveAction)) {
+ return null;
+ }
+ String normalizedAction = approveAction.trim().toUpperCase(Locale.ROOT);
+ return "APPROVED".equals(normalizedAction) || "REJECTED".equals(normalizedAction)
+ ? normalizedAction
+ : null;
+ }
+
+ private ApprovalInstance getPendingApprovalInstance(Long instanceId) {
+ return this.getOne(
+ new LambdaQueryWrapper<ApprovalInstance>()
+ .eq(ApprovalInstance::getId, instanceId)
+ .eq(ApprovalInstance::getDeleted, 0)
+ .last("LIMIT 1")
+ );
+ }
+
+ private boolean updateCurrentTask(ApprovalInstanceDto approvalInstanceDto,
+ String approveAction,
+ ApprovalTask currentTask,
+ LocalDateTime now) {
+ // 浠呭厑璁稿緟瀹℃壒浠诲姟琚垚鍔熷鐞嗕竴娆★紝閬垮厤骞跺彂涓嬮噸澶嶅鎵规垚鍔熴��
+ return approvalTaskService.update(
+ Wrappers.<ApprovalTask>lambdaUpdate()
+ .eq(ApprovalTask::getId, currentTask.getId())
+ .eq(ApprovalTask::getTaskStatus, "PENDING")
+ .eq(ApprovalTask::getDeleted, 0)
+ .set(ApprovalTask::getTaskStatus, approveAction)
+ .set(ApprovalTask::getComment, approvalInstanceDto.getApproveComment())
+ .set(ApprovalTask::getApproveTime, now)
+ .set(ApprovalTask::getIsRead, (byte) 1)
+ );
+ }
+
+ private R rejectCurrentNode(ApprovalInstance instance, ApprovalInstanceNode currentNode, LocalDateTime now) {
+ if (!updateCurrentNodeStatus(currentNode.getId(), "REJECTED", now)) {
+ return R.ok("褰撳墠鑺傜偣宸插鐞嗗畬鎴�");
+ }
+
+ closePendingTasks(instance.getId(), currentNode.getId());
+ instance.setStatus("REJECTED");
+ instance.setFinishTime(now);
+ this.updateById(instance);
+ // 椹冲洖瀵瑰簲鐨勪紒涓氭柊闂伙紝 宸梾鎶ラ攢
+ if (instance.getBusinessType().equals(TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode())) {
+ enterpriseNewsMapper.update(
+ new LambdaUpdateWrapper<EnterpriseNews>()
+ .eq(EnterpriseNews::getId, instance.getBusinessId())
+ .set(EnterpriseNews::getStatus, "REJECTED")
+ );
+ }else if (instance.getBusinessType().equals(TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode())||instance.getBusinessType().equals(TypeEnums.EXPENSE_APPROVAL.getCode())) {
+ finReimbursementMapper.update(
+ new LambdaUpdateWrapper<FinReimbursement>()
+ .eq(FinReimbursement::getId, instance.getBusinessId())
+ .set(FinReimbursement::getBillStatus, "REJECTED")
+ );
+ }
+ return R.ok("瀹℃壒宸查┏鍥�");
+ }
+
+ private R approveAndMoveNext(ApprovalInstance instance,
+ ApprovalInstanceNode currentNode,
+ ApprovalInstanceDto approvalInstanceDto,
+ LocalDateTime now) {
+ if (!updateCurrentNodeStatus(currentNode.getId(), "APPROVED", now)) {
+ return R.ok("褰撳墠鑺傜偣宸插鐞嗗畬鎴�");
+ }
+
+ closePendingTasks(instance.getId(), currentNode.getId());
+
+ int nextLevel = currentNode.getLevelNo() + 1;
+ ApprovalInstanceNode nextInstanceNode = approvalInstanceNodeService.getOne(
+ new LambdaQueryWrapper<ApprovalInstanceNode>()
+ .eq(ApprovalInstanceNode::getInstanceId, instance.getId())
+ .eq(ApprovalInstanceNode::getLevelNo, nextLevel)
+ .eq(ApprovalInstanceNode::getDeleted, 0)
+ .orderByAsc(ApprovalInstanceNode::getId)
+ .last("LIMIT 1")
+ );
+
+ if (nextInstanceNode != null) {
+ if (!activateNextInstanceNode(nextInstanceNode.getId(), now)) {
+ return R.ok("涓嬩竴瀹℃壒鑺傜偣宸茶婵�娲伙紝璇峰埛鏂板悗閲嶈瘯");
+ }
+ instance.setCurrentLevel(nextLevel);
+ instance.setStatus("PENDING");
+ this.updateById(instance);
+ List<ApprovalTask> nextTasks = approvalTaskService.list(
+ Wrappers.<ApprovalTask>lambdaQuery()
+ .eq(ApprovalTask::getInstanceId, instance.getId())
+ .eq(ApprovalTask::getNodeId, nextInstanceNode.getId())
+ .eq(ApprovalTask::getTaskStatus, "PENDING")
+ .eq(ApprovalTask::getDeleted, 0)
+ );
+ sendApproveNotice(instance, nextTasks);
+ return R.ok("瀹℃壒鎴愬姛锛屽凡娴佽浆鍒颁笅涓�鑺傜偣");
+ }
+
+ ApprovalTemplateNode nextTemplateNode = approvalTemplateNodeService.getOne(
+ new LambdaQueryWrapper<ApprovalTemplateNode>()
+ .eq(ApprovalTemplateNode::getTemplateId, instance.getTemplateId())
+ .eq(ApprovalTemplateNode::getLevelNo, nextLevel)
+ .orderByAsc(ApprovalTemplateNode::getId)
+ .last("LIMIT 1")
+ );
+
+ if (nextTemplateNode == null) {
+ instance.setStatus("APPROVED");
+ instance.setFinishTime(now);
+ this.updateById(instance);
+ handleBusinessAfterApprovalFinished(instance);
+ return R.ok("瀹℃壒宸插畬鎴�");
+ }
+
+ instance.setCurrentLevel(nextLevel);
+ instance.setStatus("PENDING");
+ this.updateById(instance);
+ approveProcessConfigNodeUtils.createCurrentNodeAndTasks(instance, false);
+ sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId()));
+ return R.ok("瀹℃壒鎴愬姛锛屽凡娴佽浆鍒颁笅涓�鑺傜偣");
+ }
+
+ private boolean activateNextInstanceNode(Long nodeId, LocalDateTime now) {
+ return approvalInstanceNodeService.update(
+ Wrappers.<ApprovalInstanceNode>lambdaUpdate()
+ .eq(ApprovalInstanceNode::getId, nodeId)
+ .eq(ApprovalInstanceNode::getStatus, "WAITING")
+ .eq(ApprovalInstanceNode::getDeleted, 0)
+ .set(ApprovalInstanceNode::getStatus, "PENDING")
+ .set(ApprovalInstanceNode::getStartTime, now)
+ );
+ }
+
+ private boolean updateCurrentNodeStatus(Long nodeId, String targetStatus, LocalDateTime now) {
+ // 浠呭厑璁镐竴涓姹傚皢褰撳墠鑺傜偣浠庡緟澶勭悊鎺ㄨ繘鍒扮洰鏍囩姸鎬侊紝閬垮厤閲嶅娴佽浆銆�
+ return approvalInstanceNodeService.update(
+ Wrappers.<ApprovalInstanceNode>lambdaUpdate()
+ .eq(ApprovalInstanceNode::getId, nodeId)
+ .eq(ApprovalInstanceNode::getStatus, "PENDING")
+ .eq(ApprovalInstanceNode::getDeleted, 0)
+ .set(ApprovalInstanceNode::getStatus, targetStatus)
+ .set(ApprovalInstanceNode::getFinishTime, now)
+ );
+ }
+
+ private void handleBusinessAfterApprovalFinished(ApprovalInstance instance) {
+ String status = instance.getStatus();
+ Long businessType = instance.getBusinessType();
+ if (TypeEnums.PURCHASE_APPROVAL.getCode().equals(businessType)) {
+ handlePurchaseApprovalFinished(instance, status);
+ return;
+ }
+ if (TypeEnums.QUOTATION_APPROVAL.getCode().equals(businessType)) {
+ handleSalesQuotationApprovalFinished(instance, status);
+ return;
+ }
+ if (TypeEnums.SHIPPING_APPROVAL.getCode().equals(businessType)) {
+ handleShippingApprovalFinished(instance, status);
+ return;
+ }
+ if (TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode().equals(businessType)
+ || TypeEnums.EXPENSE_APPROVAL.getCode().equals(businessType)) {
+ handleReimbursementApprovalFinished(instance, status);
+ return;
+ }
+ // 椹冲洖瀵瑰簲鐨勪紒涓氭柊闂汇�佸姞鐝敵璇枫�佽鍋囩敵璇峰彲浠ラ噸鏂板啀鎻愪氦
+ if (TypeEnums.LEAVE_APPROVAL.getCode().equals(businessType)
+ || TypeEnums.OVERTIME_APPROVAL.getCode().equals(businessType)) {
+ handleHolidayApplicationApprovalFinished(instance, status);
+ return;
+ }
+ if (TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode().equals(businessType)) {
+ handleNewsApprovalFinished(instance, status);
+ }
+ }
+
+ private void handleReimbursementApprovalFinished(ApprovalInstance instance, String status) {
+ if (instance == null || instance.getBusinessId() == null) {
+ return;
+ }
+
+ FinReimbursement reimbursement = new FinReimbursement();
+ reimbursement.setId(instance.getBusinessId());
+ if ("APPROVED".equals(status)) {
+ reimbursement.setBillStatus("APPROVED");
+ reimbursement.setApprovedTime(instance.getFinishTime());
+ } else if ("REJECTED".equals(status)) {
+ reimbursement.setBillStatus("REJECTED");
+ } else if ("PENDING".equals(status)) {
+ reimbursement.setBillStatus("IN_APPROVAL");
+ } else {
+ return;
+ }
+ finReimbursementMapper.updateById(reimbursement);
+ }
+
+ private void handleNewsApprovalFinished(ApprovalInstance instance, String status) {
+ if (instance == null || instance.getBusinessId() == null) {
+ return;
+ }
+ EnterpriseNews enterpriseNews = new EnterpriseNews();
+ enterpriseNews.setId(instance.getBusinessId());
+ if ("APPROVED".equals(status)) {
+ enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_PUBLISHED);
+ enterpriseNewsMapper.updateById(enterpriseNews);
+ sendEnterpriseNewsNotice(instance.getBusinessId());
+ return;
+ }
+ if ("REJECTED".equals(status)) {
+ enterpriseNews.setStatus(ENTERPRISE_NEWS_STATUS_REJECTED);
+ enterpriseNewsMapper.updateById(enterpriseNews);
+ }
+ }
+
+ private void handleHolidayApplicationApprovalFinished(ApprovalInstance instance, String status) {
+ if (instance == null || instance.getBusinessId() == null) {
+ return;
+ }
+ HolidayApplication holidayApplication = new HolidayApplication();
+ holidayApplication.setId(instance.getBusinessId());
+ if ("APPROVED".equals(status)) {
+ holidayApplication.setStatus("APPROVED");
+ } else if ("REJECTED".equals(status)) {
+ holidayApplication.setStatus("REJECTED");
+ } else if ("PENDING".equals(status)) {
+ holidayApplication.setStatus("PENDING");
+ } else {
+ return;
+ }
+ holidayApplicationMapper.updateById(holidayApplication);
+ }
+
+ private void handlePurchaseApprovalFinished(ApprovalInstance instance, String status) {
+ PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(
+ new LambdaQueryWrapper<PurchaseLedger>()
+ .eq(PurchaseLedger::getId, instance.getBusinessId())
+ .last("limit 1")
+ );
+ if (purchaseLedger == null) {
+ return;
+ }
+
+ if ("APPROVED".equals(status)) {
+ purchaseLedger.setApprovalStatus(ApprovalStatusEnum.APPROVED.getCode());
+ List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(
+ new QueryWrapper<SalesLedgerProduct>().lambda()
+ .eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
+ .eq(SalesLedgerProduct::getType, 2)
+ );
+ for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
+ if (salesLedgerProduct.getIsChecked()) {
+ qualityInspectHelper.addQualityInspect(purchaseLedger, salesLedgerProduct);
+ } else {
+ stockUtils.addStockWithBatchNo(
+ salesLedgerProduct.getProductModelId(),
+ salesLedgerProduct.getQuantity(),
+ StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
+ purchaseLedger.getId(),
+ purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId()
+ );
+ }
+ }
+ } else if ("REJECTED".equals(status)) {
+ purchaseLedger.setApprovalStatus(ApprovalStatusEnum.REJECTED.getCode());
+ } else if ("PENDING".equals(status)) {
+ purchaseLedger.setApprovalStatus(ApprovalStatusEnum.IN_PROGRESS.getCode());
+ }
+ purchaseLedgerMapper.updateById(purchaseLedger);
+ }
+
+ private void handleSalesQuotationApprovalFinished(ApprovalInstance instance, String status) {
+ SalesQuotation salesQuote = salesQuotationMapper.selectOne(
+ new LambdaQueryWrapper<SalesQuotation>()
+ .eq(SalesQuotation::getId, instance.getBusinessId())
+ .last("limit 1")
+ );
+ if (salesQuote == null) {
+ return;
+ }
+
+ if ("APPROVED".equals(status)) {
+ salesQuote.setStatus(SalesQuotationStatusEnum.APPROVED.getCode());
+ } else if ("REJECTED".equals(status)) {
+ salesQuote.setStatus(SalesQuotationStatusEnum.REJECTED.getCode());
+ } else if ("PENDING".equals(status)) {
+ salesQuote.setStatus(SalesQuotationStatusEnum.IN_PROGRESS.getCode());
+ }
+ salesQuotationMapper.updateById(salesQuote);
+ }
+
+ private void handleShippingApprovalFinished(ApprovalInstance instance, String status) {
+ ShippingInfo shippingInfo = shippingInfoMapper.selectOne(
+ new LambdaQueryWrapper<ShippingInfo>()
+ .eq(ShippingInfo::getId, instance.getTitle())
+ .orderByDesc(ShippingInfo::getCreateTime)
+ .last("limit 1")
+ );
+ if (shippingInfo == null) {
+ return;
+ }
+
+ if ("APPROVED".equals(status)) {
+ shippingInfo.setStatus(ShippingStatusEnum.APPROVED.getCode());
+ shippingInfo.setShippingDate(new Date());
+ stockUtils.shipmentStatus(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), shippingInfo.getId());
+ } else if ("REJECTED".equals(status)) {
+ stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
+ shippingInfo.setStatus(ShippingStatusEnum.REJECTED.getCode());
+ } else if ("PENDING".equals(status)) {
+ shippingInfo.setStatus(ShippingStatusEnum.IN_PROGRESS.getCode());
+ }
+ shippingInfoMapper.updateById(shippingInfo);
+ }
+
+ private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) {
+ List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverMapper.selectList(
+ new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
+ .eq(ApprovalTemplateNodeApprover::getTemplateId, instance.getTemplateId())
+ .eq(ApprovalTemplateNodeApprover::getNodeId, templateNode.getId())
+ .eq(ApprovalTemplateNodeApprover::getDeleted, 0L)
+ .orderByAsc(ApprovalTemplateNodeApprover::getSortNo)
+ );
+ if (approvers == null || approvers.isEmpty()) {
+ throw new RuntimeException("涓嬩竴瀹℃壒鑺傜偣鏈厤缃鎵逛汉");
+ }
+
+ ApprovalInstanceNode instanceNode = new ApprovalInstanceNode();
+ instanceNode.setInstanceId(instance.getId());
+ instanceNode.setLevelNo(templateNode.getLevelNo());
+ instanceNode.setApproveType(templateNode.getApproveType());
+ instanceNode.setStatus("PENDING");
+ instanceNode.setStartTime(LocalDateTime.now());
+ instanceNode.setDeleted((byte) 0);
+ approvalInstanceNodeService.save(instanceNode);
+
+ List<ApprovalTask> taskList = new ArrayList<>(approvers.size());
+ for (ApprovalTemplateNodeApprover approver : approvers) {
+ ApprovalTask task = new ApprovalTask();
+ task.setInstanceId(instance.getId());
+ task.setNodeId(instanceNode.getId());
+ task.setLevelNo(instanceNode.getLevelNo());
+ task.setApproverId(approver.getApproverId());
+ task.setApproverName(approver.getApproverName());
+ task.setTaskStatus("PENDING");
+ task.setIsRead((byte) 0);
+ task.setDeleted((byte) 0);
+ taskList.add(task);
+ }
+ approvalTaskService.saveBatch(taskList);
+ return taskList;
+ }
+
+ private void sendApproveNotice(ApprovalInstance instance, List<ApprovalTask> tasks) {
+ if (instance == null || tasks == null || tasks.isEmpty()) {
+ return;
+ }
+
+ List<Long> approverIds = tasks.stream()
+ .map(ApprovalTask::getApproverId)
+ .filter(id -> id != null && id > 0)
+ .distinct()
+ .collect(Collectors.toList());
+ if (approverIds.isEmpty()) {
+ return;
+ }
+
+ String title = StringUtils.hasText(instance.getTemplateName()) ? instance.getTemplateName() : "瀹℃壒鎻愰啋";
+ String message = "瀹℃壒鍗曞彿 " + instance.getInstanceNo() + " 闇�瑕佹偍瀹℃壒";
+ String jumpPath = "/officeProcessAutomation/ApproveManage/approve-list?id=" + instance.getId();
+ sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath);
+ }
+
+ private void sendEnterpriseNewsNotice(Long newsId) {
+ EnterpriseNews enterpriseNews = enterpriseNewsMapper.selectById(newsId);
+ if (enterpriseNews == null) {
+ return;
+ }
+ List<Long> userIds = getEnterpriseNewsNoticeUserIds(enterpriseNews);
+ if (userIds == null || userIds.isEmpty()) {
+ return;
+ }
+ String title = "浼佷笟鏂伴椈";
+ String message = "鎮ㄦ湁鏂扮殑浼佷笟鏂伴椈銆�" + enterpriseNews.getTitle() + "銆嬭鍙婃椂鏌ラ槄";
+ String jumpPath = "/officeProcessAutomation/EnterpriseNews?id=" + newsId;
+ sysNoticeService.simpleNoticeByUser(title, message, userIds, jumpPath);
+ }
+
+ private List<Long> getEnterpriseNewsNoticeUserIds(EnterpriseNews enterpriseNews) {
+ if (enterpriseNews == null || !org.springframework.util.StringUtils.hasText(enterpriseNews.getReadScope())) {
+ return Collections.emptyList();
+ }
+ String readScope = enterpriseNews.getReadScope().trim();
+ if ("all".equals(readScope)) {
+ return sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>()
+ .select(SysUser::getUserId)
+ .eq(SysUser::getDelFlag, "0"))
+ .stream()
+ .map(SysUser::getUserId)
+ .filter(id -> id != null && id > 0)
+ .distinct()
+ .collect(Collectors.toList());
+ }
+ if ("dept".equals(readScope)) {
+ List<Long> deptIds = enterpriseNewsScopeDeptMapper.selectList(
+ new LambdaQueryWrapper<EnterpriseNewsScopeDept>()
+ .eq(EnterpriseNewsScopeDept::getNewsId, enterpriseNews.getId()))
+ .stream()
+ .map(EnterpriseNewsScopeDept::getDeptId)
+ .filter(id -> id != null && id > 0)
+ .distinct()
+ .collect(Collectors.toList());
+ if (deptIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return sysUserDeptMapper.selectDistinctUserIdsByDeptIds(collectDeptIdsWithChildren(deptIds));
+ }
+ if ("custom".equals(readScope)) {
+ return enterpriseNewsScopeUserMapper.selectList(
+ new LambdaQueryWrapper<EnterpriseNewsScopeUser>()
+ .eq(EnterpriseNewsScopeUser::getNewsId, enterpriseNews.getId()))
+ .stream()
+ .map(EnterpriseNewsScopeUser::getUserId)
+ .filter(id -> id != null && id > 0)
+ .distinct()
+ .collect(Collectors.toList());
+ }
+ return Collections.emptyList();
+ }
+
+ private List<Long> collectDeptIdsWithChildren(List<Long> deptIds) {
+ Set<Long> allDeptIds = new LinkedHashSet<>();
+ for (Long deptId : deptIds) {
+ if (deptId == null) {
+ continue;
+ }
+ allDeptIds.add(deptId);
+ List<SysDept> children = sysDeptMapper.selectChildrenDeptById(deptId);
+ if (children != null && !children.isEmpty()) {
+ for (SysDept child : children) {
+ if (child != null && child.getDeptId() != null) {
+ allDeptIds.add(child.getDeptId());
+ }
+ }
+ }
+ }
+ return new ArrayList<>(allDeptIds);
+ }
+
+ private void closePendingTasks(Long instanceId, Long nodeId) {
+ LambdaUpdateWrapper<ApprovalTask> updateWrapper = Wrappers.lambdaUpdate();
+ updateWrapper.eq(ApprovalTask::getInstanceId, instanceId)
+ .eq(ApprovalTask::getNodeId, nodeId)
+ .eq(ApprovalTask::getTaskStatus, "PENDING")
+ .eq(ApprovalTask::getDeleted, 0)
+ .set(ApprovalTask::getDeleted, (byte) 1);
+ approvalTaskService.update(updateWrapper);
+ }
+
+ private void saveApprovalRecord(Long instanceId,
+ Long nodeId,
+ Long taskId,
+ Long operatorId,
+ String operatorName,
+ String action,
+ String comment) {
+ ApprovalRecord record = new ApprovalRecord();
+ record.setInstanceId(instanceId);
+ record.setNodeId(nodeId);
+ record.setTaskId(taskId);
+ record.setOperatorId(operatorId);
+ record.setOperatorName(operatorName);
+ record.setAction(action);
+ record.setComment(comment);
+ record.setDeleted((byte) 0);
+ approvalRecordService.save(record);
+ }
+
+
+}
--
Gitblit v1.9.3