| | |
| | | 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.sales.pojo.ShippingInfo; |
| | | import com.ruoyi.staff.mapper.HolidayApplicationMapper; |
| | | import com.ruoyi.staff.pojo.HolidayApplication; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.ruoyi.device.pojo.DeviceStatusChangeRecord; |
| | | import com.ruoyi.device.service.IDeviceStatusChangeRecordService; |
| | | import com.ruoyi.device.pojo.DeviceLedger; |
| | | import com.ruoyi.device.service.IDeviceLedgerService; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | private final EnterpriseNewsMapper enterpriseNewsMapper; |
| | | private final EnterpriseNewsScopeDeptMapper enterpriseNewsScopeDeptMapper; |
| | | private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper; |
| | | private final IDeviceStatusChangeRecordService deviceStatusChangeRecordService; |
| | | private final IDeviceLedgerService deviceLedgerService; |
| | | |
| | | @Override |
| | | public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) { |
| | |
| | | } |
| | | records.forEach(vo -> { |
| | | vo.setBusinessName(TypeEnums.getLabelByValue(vo.getBusinessType())); |
| | | |
| | | // 根据业务类型查询对应的单号 |
| | | if (vo.getBusinessType() != null && vo.getBusinessId() != null) { |
| | | if (TypeEnums.PURCHASE_APPROVAL.getCode().equals(vo.getBusinessType())) { |
| | | // 采购审批 - 查询采购单号 |
| | | PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(vo.getBusinessId()); |
| | | if (purchaseLedger != null) { |
| | | vo.setPurchaseContractNumber(purchaseLedger.getPurchaseContractNumber()); |
| | | } |
| | | } else if (TypeEnums.QUOTATION_APPROVAL.getCode().equals(vo.getBusinessType())) { |
| | | // 报价审批 - 查询报价单号 |
| | | SalesQuotation salesQuotation = salesQuotationMapper.selectById(vo.getBusinessId()); |
| | | if (salesQuotation != null) { |
| | | vo.setQuotationNo(salesQuotation.getQuotationNo()); |
| | | } |
| | | } else if (TypeEnums.SHIPPING_APPROVAL.getCode().equals(vo.getBusinessType())) { |
| | | // 发货审批 - 查询发货单号 |
| | | ShippingInfo shippingInfo = shippingInfoMapper.selectById(vo.getBusinessId()); |
| | | if (shippingInfo != null) { |
| | | vo.setShippingNo(shippingInfo.getShippingNo()); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | Long currentUserId = SecurityUtils.getUserId(); |
| | | |
| | |
| | | @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); |
| | | |
| | | if (approvalInstanceDto.getApplicantId() == null) { |
| | | approvalInstanceDto.setApplicantId(SecurityUtils.getUserId()); |
| | | LoginUser loginUser = SecurityUtils.getLoginUser(); |
| | | if (loginUser != null && loginUser.getUser() != null) { |
| | | approvalInstanceDto.setApplicantName(loginUser.getUser().getNickName()); |
| | | } |
| | | } |
| | | |
| | | // 校验设备状态变更审批:如果该设备已有正在审批的任务,无法再次进行审批 |
| | | if (TypeEnums.DEVICE_STATUS_CHANGE_APPROVAL.getCode().equals(approvalInstanceDto.getBusinessType())) { |
| | | Long deviceId = approvalInstanceDto.getBusinessId(); |
| | | |
| | | long pendingCount = deviceStatusChangeRecordService.count(Wrappers.<DeviceStatusChangeRecord>lambdaQuery() |
| | | .eq(DeviceStatusChangeRecord::getDeviceId, deviceId) |
| | | .eq(DeviceStatusChangeRecord::getApprovalStatus, "PENDING") |
| | | .eq(DeviceStatusChangeRecord::getDeleted, 0) |
| | | ); |
| | | if (pendingCount > 0) { |
| | | throw new ServiceException("该设备已有正在进行的状态变更审批,无法再次提交"); |
| | | } |
| | | |
| | | DeviceLedger device = deviceLedgerService.getById(deviceId); |
| | | if (device == null) { |
| | | throw new ServiceException("设备不存在"); |
| | | } |
| | | |
| | | Integer targetStatus = null; |
| | | String reason = ""; |
| | | if (StringUtils.hasText(approvalInstanceDto.getFormConfig())) { |
| | | try { |
| | | JSONObject formObj = JSONObject.parseObject(approvalInstanceDto.getFormConfig()); |
| | | if (formObj.containsKey("targetStatus")) { |
| | | targetStatus = formObj.getInteger("targetStatus"); |
| | | } else if (formObj.containsKey("status")) { |
| | | targetStatus = formObj.getInteger("status"); |
| | | } |
| | | if (formObj.containsKey("reason")) { |
| | | reason = formObj.getString("reason"); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("解析状态变更表单失败", e); |
| | | } |
| | | } |
| | | |
| | | DeviceStatusChangeRecord record = new DeviceStatusChangeRecord(); |
| | | record.setDeviceId(deviceId); |
| | | record.setOriginalStatus(Integer.valueOf(device.getStatus())); |
| | | record.setTargetStatus(targetStatus); |
| | | record.setReason(reason); |
| | | record.setApprovalStatus("PENDING"); |
| | | deviceStatusChangeRecordService.save(record); |
| | | |
| | | // 绑定到关联记录的主键 |
| | | approvalInstanceDto.setBusinessId(record.getId()); |
| | | } |
| | | |
| | | boolean saved = this.save(approvalInstanceDto); |
| | | if (!saved) { |
| | | return false; |
| | |
| | | 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) { |
| | |
| | | ); |
| | | //审批拒绝的处理 |
| | | if ("REJECTED".equals(approveAction)) { |
| | | return rejectCurrentNode(instance, currentNode, now); |
| | | return rejectCurrentNode(instance, currentNode, approvalInstanceDto.getApproveComment(), now); |
| | | } |
| | | if (!approveProcessConfigNodeUtils.canProceedToNextLevel(instance.getId(), currentNode.getApproveType())) { |
| | | return R.ok("审批成功,等待其他审批人处理"); |
| | | } |
| | | |
| | | return approveAndMoveNext(instance, currentNode, approvalInstanceDto, now); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public R autoApprove(Long instanceId) { |
| | | if (instanceId == null) { |
| | | return R.fail("审批实例 ID 不能为空"); |
| | | } |
| | | |
| | | ApprovalInstance instance = getPendingApprovalInstance(instanceId); |
| | | if (instance == null) { |
| | | return R.fail("审批实例不存在"); |
| | | } |
| | | if ("REJECTED".equals(instance.getStatus())) { |
| | | return R.fail("审批已驳回,无法自动通过"); |
| | | } |
| | | if ("APPROVED".equals(instance.getStatus())) { |
| | | return R.ok("审批已完成"); |
| | | } |
| | | |
| | | ApprovalInstanceDto autoApproveDto = new ApprovalInstanceDto(); |
| | | autoApproveDto.setId(instanceId); |
| | | autoApproveDto.setApproveComment("系统自动审批"); |
| | | |
| | | int loopCount = 0; |
| | | while (loopCount++ < 20) { |
| | | ApprovalInstance currentInstance = getPendingApprovalInstance(instanceId); |
| | | if (currentInstance == null) { |
| | | return R.fail("审批实例不存在"); |
| | | } |
| | | if ("APPROVED".equals(currentInstance.getStatus())) { |
| | | return R.ok("审批已完成"); |
| | | } |
| | | if ("REJECTED".equals(currentInstance.getStatus())) { |
| | | return R.fail("审批已驳回,无法自动通过"); |
| | | } |
| | | |
| | | ApprovalInstanceNode currentNode = approveProcessConfigNodeUtils.getCurrentNode(currentInstance.getId()); |
| | | if (currentNode == null) { |
| | | currentInstance.setStatus("APPROVED"); |
| | | currentInstance.setFinishTime(LocalDateTime.now()); |
| | | this.updateById(currentInstance); |
| | | handleBusinessAfterApprovalFinished(currentInstance, null); |
| | | return R.ok("审批已完成"); |
| | | } |
| | | |
| | | List<ApprovalTask> pendingTasks = approvalTaskService.list( |
| | | Wrappers.<ApprovalTask>lambdaQuery() |
| | | .eq(ApprovalTask::getInstanceId, currentInstance.getId()) |
| | | .eq(ApprovalTask::getNodeId, currentNode.getId()) |
| | | .eq(ApprovalTask::getTaskStatus, "PENDING") |
| | | .eq(ApprovalTask::getDeleted, 0) |
| | | ); |
| | | |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | for (ApprovalTask currentTask : pendingTasks) { |
| | | if (!updateCurrentTask(autoApproveDto, "APPROVED", currentTask, now)) { |
| | | return R.fail("当前任务已被处理,请刷新后重试"); |
| | | } |
| | | saveApprovalRecord( |
| | | currentInstance.getId(), |
| | | currentNode.getId(), |
| | | currentTask.getId(), |
| | | 0L, |
| | | "系统自动审批", |
| | | "APPROVED", |
| | | autoApproveDto.getApproveComment() |
| | | ); |
| | | } |
| | | |
| | | if (!approveProcessConfigNodeUtils.canProceedToNextLevel(currentInstance.getId(), currentNode.getApproveType())) { |
| | | return R.ok("审批成功,等待其他审批人处理"); |
| | | } |
| | | |
| | | R moveResult = moveToNextLevel(currentInstance, currentNode, autoApproveDto, now, false); |
| | | if (!R.isSuccess(moveResult)) { |
| | | return moveResult; |
| | | } |
| | | } |
| | | |
| | | return R.fail("自动审批循环次数超限"); |
| | | } |
| | | |
| | | private String normalizeApproveAction(String approveAction) { |
| | |
| | | ); |
| | | } |
| | | |
| | | private R rejectCurrentNode(ApprovalInstance instance, ApprovalInstanceNode currentNode, LocalDateTime now) { |
| | | private R rejectCurrentNode(ApprovalInstance instance, ApprovalInstanceNode currentNode, String approveComment, LocalDateTime now) { |
| | | if (!updateCurrentNodeStatus(currentNode.getId(), "REJECTED", now)) { |
| | | 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") |
| | | ); |
| | | } |
| | | // 统一处理业务状态更新 |
| | | handleBusinessAfterApprovalFinished(instance, approveComment); |
| | | return R.ok("审批已驳回"); |
| | | } |
| | | |
| | |
| | | ApprovalInstanceNode currentNode, |
| | | ApprovalInstanceDto approvalInstanceDto, |
| | | LocalDateTime now) { |
| | | return moveToNextLevel(instance, currentNode, approvalInstanceDto, now, true); |
| | | } |
| | | |
| | | private R moveToNextLevel(ApprovalInstance instance, |
| | | ApprovalInstanceNode currentNode, |
| | | ApprovalInstanceDto approvalInstanceDto, |
| | | LocalDateTime now, |
| | | boolean notifyNextNode) { |
| | | if (!updateCurrentNodeStatus(currentNode.getId(), "APPROVED", 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); |
| | | if (notifyNextNode) { |
| | | 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("审批成功,已流转到下一节点"); |
| | | } |
| | | |
| | |
| | | instance.setStatus("APPROVED"); |
| | | instance.setFinishTime(now); |
| | | this.updateById(instance); |
| | | handleBusinessAfterApprovalFinished(instance); |
| | | handleBusinessAfterApprovalFinished(instance, null); |
| | | return R.ok("审批已完成"); |
| | | } |
| | | |
| | |
| | | instance.setStatus("PENDING"); |
| | | this.updateById(instance); |
| | | approveProcessConfigNodeUtils.createCurrentNodeAndTasks(instance, false); |
| | | sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId())); |
| | | if (notifyNextNode) { |
| | | sendApproveNotice(instance, approveProcessConfigNodeUtils.getCurrentPendingTasks(approvalInstanceDto.getId())); |
| | | } |
| | | return R.ok("审批成功,已流转到下一节点"); |
| | | } |
| | | |
| | |
| | | ); |
| | | } |
| | | |
| | | private void handleBusinessAfterApprovalFinished(ApprovalInstance instance) { |
| | | private void handleBusinessAfterApprovalFinished(ApprovalInstance instance, String rejectReason) { |
| | | String status = instance.getStatus(); |
| | | Long businessType = instance.getBusinessType(); |
| | | if (TypeEnums.PURCHASE_APPROVAL.getCode().equals(businessType)) { |
| | |
| | | } |
| | | if (TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode().equals(businessType)) { |
| | | handleNewsApprovalFinished(instance, status); |
| | | return; |
| | | } |
| | | if (TypeEnums.DEVICE_STATUS_CHANGE_APPROVAL.getCode().equals(businessType)) { |
| | | handleDeviceStatusChangeApprovalFinished(instance, status, rejectReason); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | private void handleDeviceStatusChangeApprovalFinished(ApprovalInstance instance, String status, String rejectReason) { |
| | | if (instance == null || instance.getBusinessId() == null) { |
| | | return; |
| | | } |
| | | DeviceStatusChangeRecord record = deviceStatusChangeRecordService.getById(instance.getBusinessId()); |
| | | if (record == null) { |
| | | return; |
| | | } |
| | | if ("APPROVED".equals(status)) { |
| | | record.setApprovalStatus("APPROVED"); |
| | | if (record.getTargetStatus() != null) { |
| | | DeviceLedger device = new DeviceLedger(); |
| | | device.setId(record.getDeviceId()); |
| | | device.setStatus(String.valueOf(record.getTargetStatus())); |
| | | deviceLedgerService.updateById(device); |
| | | } |
| | | } else if ("REJECTED".equals(status)) { |
| | | record.setApprovalStatus("REJECTED"); |
| | | if (rejectReason != null) { |
| | | record.setRejectReason(rejectReason); |
| | | } |
| | | } else if ("PENDING".equals(status)) { |
| | | record.setApprovalStatus("PENDING"); |
| | | } |
| | | deviceStatusChangeRecordService.updateById(record); |
| | | } |
| | | |
| | | private void handleReimbursementApprovalFinished(ApprovalInstance instance, String status) { |
| | |
| | | private void handlePurchaseApprovalFinished(ApprovalInstance instance, String status) { |
| | | PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne( |
| | | new LambdaQueryWrapper<PurchaseLedger>() |
| | | .eq(PurchaseLedger::getPurchaseContractNumber, instance.getTitle()) |
| | | .eq(PurchaseLedger::getId, instance.getBusinessId()) |
| | | .last("limit 1") |
| | | ); |
| | | if (purchaseLedger == null) { |
| | |
| | | private void handleSalesQuotationApprovalFinished(ApprovalInstance instance, String status) { |
| | | SalesQuotation salesQuote = salesQuotationMapper.selectOne( |
| | | new LambdaQueryWrapper<SalesQuotation>() |
| | | .eq(SalesQuotation::getQuotationNo, instance.getTitle()) |
| | | .eq(SalesQuotation::getId, instance.getBusinessId()) |
| | | .last("limit 1") |
| | | ); |
| | | if (salesQuote == null) { |
| | |
| | | |
| | | String title = StringUtils.hasText(instance.getTemplateName()) ? instance.getTemplateName() : "审批提醒"; |
| | | String message = "审批单号 " + instance.getInstanceNo() + " 需要您审批"; |
| | | String jumpPath = "/officeProcessAutomation/ApproveManage/approve-list?id=" + instance.getId(); |
| | | String jumpPath = getJumpPathByBusinessType(instance.getBusinessType(), instance.getId()); |
| | | sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath); |
| | | } |
| | | |
| | | private String getJumpPathByBusinessType(Long businessType, Long instanceId) { |
| | | if (businessType == null) { |
| | | return "/collaborativeApproval/approve-list?id=" + instanceId; |
| | | } |
| | | if (TypeEnums.LEAVE_APPROVAL.getCode().equals(businessType)) { |
| | | return "/collaborativeApproval/AttendManage/leave-apply?id=" + instanceId; |
| | | } |
| | | if (TypeEnums.OVERTIME_APPROVAL.getCode().equals(businessType)) { |
| | | return "/collaborativeApproval/AttendManage/overtime-apply?id=" + instanceId; |
| | | } |
| | | if (TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode().equals(businessType)) { |
| | | return "/collaborativeApproval/ReimburseManage/travel-reimburse?id=" + instanceId; |
| | | } |
| | | if (TypeEnums.EXPENSE_APPROVAL.getCode().equals(businessType)) { |
| | | return "/collaborativeApproval/ReimburseManage/cost-reimburse?id=" + instanceId; |
| | | } |
| | | return "/collaborativeApproval/approve-list?id=" + instanceId; |
| | | } |
| | | |
| | | private void sendEnterpriseNewsNotice(Long newsId) { |
| | | EnterpriseNews enterpriseNews = enterpriseNewsMapper.selectById(newsId); |
| | | if (enterpriseNews == null) { |