| | |
| | | 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.ApprovalTemplateMapper; |
| | | 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.mapper.QualityInspectMapper; |
| | | import com.ruoyi.quality.mapper.QualityInspectParamMapper; |
| | | import com.ruoyi.quality.mapper.QualityTestStandardMapper; |
| | | import com.ruoyi.quality.mapper.QualityTestStandardParamMapper; |
| | | import com.ruoyi.quality.utils.QualityInspectHelper; |
| | | import com.ruoyi.sales.mapper.SalesLedgerProductMapper; |
| | | import com.ruoyi.sales.mapper.SalesQuotationMapper; |
| | |
| | | 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; |
| | |
| | | @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 ApprovalTemplateNodeApproverService approvalTemplateNodeApproverService; |
| | | 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 QualityInspectMapper qualityInspectMapper; |
| | | private final QualityTestStandardMapper qualityTestStandardMapper; |
| | | private final QualityTestStandardParamMapper qualityTestStandardParamMapper; |
| | | private final QualityInspectParamMapper qualityInspectParamMapper; |
| | | private final SalesQuotationMapper salesQuotationMapper; |
| | | private final ShippingInfoMapper shippingInfoMapper; |
| | | private final ApprovalTemplateMapper approvalTemplateMapper; |
| | | 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) { |
| | |
| | | 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())); |
| | | } |
| | | |
| | | } |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Boolean add(ApprovalInstanceDto approvalInstanceDto) { |
| | | String instanceNo = OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no"); |
| | | String instanceNo = OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no", approvalInstanceDto.getCreateTime() != null ? approvalInstanceDto.getCreateTime() : LocalDateTime.now()); |
| | | approvalInstanceDto.setInstanceNo(instanceNo); |
| | | approvalInstanceDto.setStatus("PENDING"); |
| | | approvalInstanceDto.setCurrentLevel(1); |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | if (ids == null || ids.isEmpty()) { |
| | | return false; |
| | | } |
| | | fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.APPROVAL_INSTANCE, ids); |
| | | |
| | | int instanceRows = approvalInstanceMapper.update( |
| | | null, |
| | |
| | | approveAction, |
| | | approvalInstanceDto.getApproveComment() |
| | | ); |
| | | |
| | | //审批拒绝的处理 |
| | | if ("REJECTED".equals(approveAction)) { |
| | | return rejectCurrentNode(instance, currentNode, now); |
| | | } |
| | | |
| | | if (!approveProcessConfigNodeUtils.canProceedToNextLevel(instance.getId(), currentNode.getApproveType())) { |
| | | return R.ok("审批成功,等待其他审批人处理"); |
| | | } |
| | |
| | | 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("审批已驳回"); |
| | | } |
| | | |
| | |
| | | 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()) |
| | |
| | | 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) { |
| | |
| | | } |
| | | 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) { |
| | |
| | | } |
| | | |
| | | private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) { |
| | | List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverService.list( |
| | | List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverMapper.selectList( |
| | | new LambdaQueryWrapper<ApprovalTemplateNodeApprover>() |
| | | .eq(ApprovalTemplateNodeApprover::getTemplateId, instance.getTemplateId()) |
| | | .eq(ApprovalTemplateNodeApprover::getNodeId, templateNode.getId()) |
| | |
| | | |
| | | String title = StringUtils.hasText(instance.getTemplateName()) ? instance.getTemplateName() : "审批提醒"; |
| | | String message = "审批单号 " + instance.getInstanceNo() + " 需要您审批"; |
| | | String jumpPath = "/approvalInstance?id=" + instance.getId(); |
| | | 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) |