@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.service.task;
 
		
	
		
			
				import   cn.hutool.core.collection.CollUtil ;  
		
	
		
			
				import   cn.hutool.core.util.* ;  
		
	
		
			
				import   cn.iocoder.yudao.framework.common.pojo.PageResult ;  
		
	
		
			
				import   cn.iocoder.yudao.framework.common.util.collection.CollectionUtils ;  
		
	
		
			
				import   cn.iocoder.yudao.framework.common.util.date.DateUtils ;  
		
	
		
			
				import   cn.iocoder.yudao.framework.common.util.number.NumberUtils ;  
		
	
		
			
				import   cn.iocoder.yudao.framework.common.util.object.PageUtils ;  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -53,8 +52,6 @@ import java.util.stream.Stream;
 
		
	
		
			
				import static   cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception ;  
		
	
		
			
				import static   cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.* ;  
		
	
		
			
				import static   cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.* ;  
		
	
		
			
				import static   cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum.REJECT_BY_ADD_SIGN_TASK_REJECT ;  
		
	
		
			
				import static   cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum.AUTO_REJECT_BY_ADD_SIGN_REJECT ;  
		
	
		
			
				 
		
	
		
			
				/**  
		
	
		
			
				 * 流程任务实例 Service 实现类  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -329,35 +326,41 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 
		
	
		
			
				         if   ( instance   = =   null )   {  
		
	
		
			
				             throw   exception ( PROCESS_INSTANCE_NOT_EXISTS ) ;  
		
	
		
			
				         }  
		
	
		
			
				 
		
	
		
			
				         // 2. 处理当前任务  
		
	
		
			
				         // 2.1 更新流程任务为不通过  
		
	
		
			
				         updateTaskStatusAndReason ( task . getId ( ) ,   BpmTaskStatusEnum . REJECT . getStatus ( ) ,   reqVO . getReason ( ) ) ;  
		
	
		
			
				         // 2.2 添加评论  
		
	
		
			
				         taskService . addComment ( task . getId ( ) ,   task . getProcessInstanceId ( ) ,   BpmCommentTypeEnum . REJECT . getType ( ) ,  
		
	
		
			
				                 BpmCommentTypeEnum . REJECT . formatComment ( reqVO . getReason ( ) ) ) ;  
		
	
		
			
				 
		
	
		
			
				         // 3.1 如果是被加签任务且是后加签。 更新加签任务状态为取消   
		
	
		
			
				         if   ( BpmTaskSignTypeEnum . AFTER . getType ( ) . equals ( task . getScopeType ( ) ) )   {  
		
	
		
			
				             List < Task >   childTaskList   =   getTaskListByParentTaskId ( task . getId ( ) ) ;   
		
	
		
			
				             updateTaskStatusWhenCanceled ( childTaskList ,   reqVO . getReason ( ) ) ;   
		
	
		
			
				         // 3. 处理其他进行中的任务   
		
	
		
			
				         // 3.1 如果当前任务时被加签的,则加它的根任务也标记成未通过  
		
	
		
			
				        // 疑问:为什么要标记未通过呢?   
		
	
		
			
				        // 回答:例如说 A 任务被向前加签除 B 任务时,    
		
	
		
			
				         if   ( task . getParentTaskId ( )   ! =   null )   {  
		
	
		
			
				             String   rootParentId   =   getTaskRootParentId ( task ) ;  
		
	
		
			
				             updateTaskStatusAndReason ( rootParentId ,   BpmTaskStatusEnum . REJECT . getStatus ( ) ,  
		
	
		
			
				                     BpmCommentTypeEnum . REJECT . formatComment ( " 加签任务不通过 " ) ) ;  
		
	
		
			
				             taskService . addComment ( rootParentId ,   task . getProcessInstanceId ( ) ,   BpmCommentTypeEnum . REJECT . getType ( ) ,  
		
	
		
			
				                     BpmCommentTypeEnum . REJECT . formatComment ( " 加签任务不通过 " ) ) ;  
		
	
		
			
				         }  
		
	
		
			
				         // 3.2 如果是加签的任务   
		
	
		
			
				         if   ( StrUtil . isNotEmpty ( task . getParentTaskId ( ) ) )   {  
		
	
		
			
				             Task   signTask   =   validateTaskExist ( task . getParentTaskId ( ) ) ;   
		
	
		
			
				             // 3.2.1 更新被加签的任务为不通过   
		
	
		
			
				             if   ( BpmTaskSignTypeEnum . BEFORE . getType ( ) . equals ( signTask . getScopeType ( ) ) )    {  
		
	
		
			
				                 updateTaskStatusAndReason ( task . getParentTaskId ( ) ,   BpmTaskStatusEnum . REJECT . getStatus ( ) ,   AUTO_REJECT_BY_ADD_SIGN_REJECT  . getReason  ( ) ) ;  
		
	
		
			
				            }   else   if   ( BpmTaskSignTypeEnum . AFTER . getType ( ) . equals ( signTask . getScopeType ( ) ) )   {   
		
	
		
			
				                 updateTaskStatus ( task . getParentTaskId ( ) ,   BpmTaskStatusEnum . REJECT . getStatus ( ) ) ;  
		
	
		
			
				                 // 后加签 不添加拒绝意见。因为会把原来的意见覆盖.  
		
	
		
			
				         // 3.2 其它未结束的任务,直接取消   
		
	
		
			
				         // 疑问:为什么不通过 updateTaskStatusWhenCanceled 监听取消,而是直接提前调用呢?  
		
	
		
			
				        // 回答:详细见 updateTaskStatusWhenCanceled 的方法,加签的场景   
		
	
		
			
				        List < Task >   taskList   =   getRunningTaskListByProcessInstanceId ( instance . getProcessInstanceId ( ) ,   null ,   null ,   null ) ;   
		
	
		
			
				        taskList . forEach ( otherTask   - >    {  
		
	
		
			
				            if   ( ! otherTask . getId ( ) . equals ( task  . getId  ( ) ) )   {   // 不需要处理当前任务  
		
	
		
			
				                 return ;   
		
	
		
			
				             }  
		
	
		
			
				             // 3.2.2 添加评论  
		
	
		
			
				             taskService . addComment ( task . getParentTaskId ( ) ,   task . getProcessInstanceId ( ) ,  
		
	
		
			
				                     BpmCommentTypeEnum . REJECT . getType ( ) ,   REJECT_BY_ADD_SIGN_TASK_REJECT . getComment ( ) )  ;  
		
	
		
			
				             // 3.2.3 更新还在进行中的加签任务状态为取消  
		
	
		
			
				             List < Task >   addSignTaskList   =   getTaskListByParentTaskId ( t ask. getParentTask Id ( ) ) ;  
		
	
		
			
				             updateTaskStatusWhenCanceled ( CollectionUtils . filterList ( addSignTaskList ,   item   - >   ! item . getId ( ) . equals ( task . getId ( ) ) ) ,   
		
	
		
			
				                     reqVO . getReason ( ) ) ;   
		
	
		
			
				        }   
		
	
		
			
				             Integer   otherTaskStatus   =   ( Integer )   task . getTaskLocalVariables ( ) . get ( BpmConstants . TASK_VARIABLE_STATUS ) ;  
		
	
		
			
				             if   ( BpmTaskStatusEnum . isEndStatus ( otherTaskStatus ) )   {  
		
	
		
			
				                return  ;  
		
	
		
			
				             }  
		
	
		
			
				             updateTaskStatusWhenCanceled ( otherT ask. getId ( ) ) ;  
		
	
		
			
				        } ) ;   
		
	
		
			
				        taskList . stream ( ) . filter ( otherTask   - >   ! otherTask . getId ( ) . equals ( task . getId ( ) ) )   // 需要排除当前任务   
		
	
		
			
				                 . forEach ( otherTask   - >   updateTaskStatusWhenCanceled ( otherTask . getId ( ) ) ) ;   
		
	
		
			
				 
		
	
		
			
				         // 4.1 驳回到指定的任务节点  
		
	
		
			
				         BpmnModel   bpmnModel   =   bpmModelService . getBpmnModelByDefinitionId ( task . getProcessDefinitionId ( ) ) ;  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -372,26 +375,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 
		
	
		
			
				             return ;  
		
	
		
			
				         }  
		
	
		
			
				 
		
	
		
			
				         // 4.2.1 更新其它正在运行的任务状态为取消。需要过滤掉当前任务和被加签的任务   
		
	
		
			
				         // TODO @jason: , ?   
		
	
		
			
				         List < Task >   taskList   =   getRunningTaskListByProcessInstanceId ( instance . getProcessInstanceId ( ) ,   false ,   null ,   null ) ;  
		
	
		
			
				         updateTaskStatusWhenCanceled (  
		
	
		
			
				                 CollectionUtils . filterList ( taskList ,   item   - >   ! item . getId ( ) . equals ( task . getId ( ) )   & &   ! item . getId ( ) . equals ( task . getParentTaskId ( ) ) ) ,  
		
	
		
			
				                 reqVO . getReason ( ) ) ;  
		
	
		
			
				         // 4.2.2 终止流程  
		
	
		
			
				         // 4.2 终止流程   
		
	
		
			
				         Set < String >   activityIds   =   convertSet ( taskList ,   Task : : getTaskDefinitionKey ) ;  
		
	
		
			
				         EndEvent   endEvent   =   BpmnModelUtils . getEndEvent ( bpmnModel ) ;  
		
	
		
			
				         Assert . notNull ( endEvent ,   " 结束节点不能未空 " ) ;  
		
	
		
			
				         processInstanceService . updateProcessInstanceReject ( instance ,   CollUtil . newArrayList ( )   endEvent . getId ( ) ,   reqVO . getReason ( ) ) ;  
		
	
		
			
				     }  
		
	
		
			
				 
		
	
		
			
				     private   void   updateTaskStatusWhenCanceled ( List < Task >   taskList ,   String   reason )   {  
		
	
		
			
				         taskList . forEach ( task   - >   {  
		
	
		
			
				             updateTaskStatusAndReason ( task . getId ( ) ,   BpmTaskStatusEnum . CANCEL . getStatus ( ) ,   BpmDeleteReasonEnum . CANCEL_BY_SYSTEM . getReason ( ) ) ;  
		
	
		
			
				             taskService . addComment ( task . getId ( ) ,   task . getProcessInstanceId ( ) ,  
		
	
		
			
				                     BpmCommentTypeEnum . CANCEL . getType ( ) ,   BpmCommentTypeEnum . CANCEL . formatComment ( reason ) ) ;  
		
	
		
			
				 
		
	
		
			
				         } ) ;  
		
	
		
			
				         processInstanceService . updateProcessInstanceReject ( instance ,   activityIds ,   endEvent . getId ( ) ,   reqVO . getReason ( ) ) ;  
		
	
		
			
				     }  
		
	
		
			
				 
		
	
		
			
				     /**  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -440,9 +428,14 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 
		
	
		
			
				         updateTaskStatus ( task . getId ( ) ,   BpmTaskStatusEnum . RUNNING . getStatus ( ) ) ;  
		
	
		
			
				     }  
		
	
		
			
				 
		
	
		
			
				     /**  
		
	
		
			
				     * 重要补充说明:该方法目前主要有两个情况会调用到:  
		
	
		
			
				     *  
		
	
		
			
				     * 1. 或签场景 + 审批通过:一个或签有多个审批时,如果 A 审批通过,其它或签 B、C 等任务会被 Flowable 自动删除,此时需要通过该方法更新状态为已取消  
		
	
		
			
				     * 2. 审批不通过:在 {@link #rejectTask(Long, BpmTaskRejectReqVO)} 不通过时,对于加签的任务,不会被 Flowable 删除,此时需要通过该方法更新状态为已取消  
		
	
		
			
				     */  
		
	
		
			
				     @Override  
		
	
		
			
				     public   void   updateTaskStatusWhenCanceled ( String   taskId )   {  
		
	
		
			
				         // @芋艿。这里是不是可以不要了,要不然。  updateTaskStatusAndReason 会报错 task 已经删除了。  
		
	
		
			
				         Task   task   =   getTask ( taskId ) ;  
		
	
		
			
				         // 1. 可能只是活动,不是任务,所以查询不到  
		
	
		
			
				         if   ( task   = =   null )   {  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -500,6 +493,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 
		
	
		
			
				                 . includeTaskLocalVariables ( ) ;  
		
	
		
			
				         if   ( BooleanUtil . isTrue ( assigned ) )   {  
		
	
		
			
				             taskQuery . taskAssigned ( ) ;  
		
	
		
			
				         }   else   if   ( BooleanUtil . isFalse ( assigned ) )   {  
		
	
		
			
				             taskQuery . taskUnassigned ( ) ;  
		
	
		
			
				         }  
		
	
		
			
				         if   ( StrUtil . isNotEmpty ( executionId ) )   {  
		
	
		
			
				             taskQuery . executionId ( executionId ) ;  
		
	
	
		
			
				
					
					
						
					 
				
			
			@@ -888,6 +883,29 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 
		
	
		
			
				         return   taskService . createNativeTaskQuery ( ) . sql ( sql ) . parameter ( " parentTaskId " ,   parentTaskId ) . count ( ) ;  
		
	
		
			
				     }  
		
	
		
			
				 
		
	
		
			
				     /**  
		
	
		
			
				     * 获得任务根任务的父任务编号  
		
	
		
			
				     *  
		
	
		
			
				     * @param task 任务  
		
	
		
			
				     * @return 根任务的父任务编号  
		
	
		
			
				     */  
		
	
		
			
				     private   String   getTaskRootParentId ( Task   task )   {  
		
	
		
			
				         if   ( task   = =   null   | |   task . getParentTaskId ( )   = =   null )   {  
		
	
		
			
				             return   null ;  
		
	
		
			
				         }  
		
	
		
			
				         for   ( int   i   =   0 ;   i   <   Short . MAX_VALUE ;   i + + )   {  
		
	
		
			
				             Task   parentTask   =   getTask ( task . getParentTaskId ( ) ) ;  
		
	
		
			
				             if   ( parentTask   = =   null )   {  
		
	
		
			
				                 return   null ;  
		
	
		
			
				             }  
		
	
		
			
				             if   ( parentTask . getParentTaskId ( )   = =   null )   {  
		
	
		
			
				                 return   parentTask . getId ( ) ;  
		
	
		
			
				             }  
		
	
		
			
				             task   =   parentTask ;  
		
	
		
			
				         }  
		
	
		
			
				         throw   new   IllegalArgumentException ( String . format ( " Task(%s) 层级过深,无法获取父节点编号 " ,   task . getId ( ) ) ) ;  
		
	
		
			
				     }  
		
	
		
			
				 
		
	
		
			
				     @Override  
		
	
		
			
				     public   Map < String ,   String >   getTaskNameByTaskIds ( Collection < String >   taskIds )   {  
		
	
		
			
				         if   ( CollUtil . isEmpty ( taskIds ) )   {