| ¶Ô±ÈÐÂÎļþ |
| | |
| | | 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); |
| | | } |
| | | |
| | | |
| | | } |