只有加签生成的任务才能进行减签!!!
此处的减签是去掉审批流程 不是去除某个审批人员而是直接减少审批环节
减签整体代码
@Transactional(rollbackFor = Exception.class)
public void deleteSignTask(Long userId, BpmTaskSignDeleteReqVO reqVO) {
// 1.1 校验 task 可以被减签
Task task = validateTaskCanSignDelete(reqVO.getId());
// 1.2 校验取消人存在
AdminUserRespDTO cancelUser = null;
if (StrUtil.isNotBlank(task.getAssignee())) {
cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee()));
}
if (cancelUser == null && StrUtil.isNotBlank(task.getOwner())) {
cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner()));
}
Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误");
// 2.1 获得子任务列表,包括子任务的子任务
List<Task> childTaskList = getAllChildTaskList(task);
childTaskList.add(task);
// 2.2 更新子任务为已取消
String cancelReason = StrUtil.format("任务被取消,原因:由于[{}]操作[减签],", cancelUser.getNickname());
childTaskList.forEach(childTask -> updateTaskStatusAndReason(childTask.getId(), BpmTaskStatusEnum.CANCEL.getStatus(), cancelReason));
// 2.3 删除任务和所有子任务
taskService.deleteTasks(convertList(childTaskList, Task::getId));
// 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录
AdminUserRespDTO user = adminUserApi.getUser(userId);
taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), BpmCommentTypeEnum.SUB_SIGN.getType(),
StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname()));
// 4. 处理当前任务的父任务
handleParentTaskIfSign(task.getParentTaskId());
}
下面对上述整体代码来做一个详细描述。
减签请求参数
@Schema(description = "管理后台 - 加签任务的删除(减签) Request VO")
@Data
public class BpmTaskSignDeleteReqVO {
@Schema(description = "被减签的任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotEmpty(message = "任务编号不能为空")
private String id;
@Schema(description = "减签原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "需要减签")
@NotEmpty(message = "减签原因不能为空")
private String reason;
}
减签请求参数比较简单只需要传入要减签的任务编号以及减签原因即可。
校验任务是否可以减签
private Task validateTaskCanSignDelete(String id) {
Task task = validateTaskExist(id);
if (task.getParentTaskId() == null) {
throw exception(TASK_SIGN_DELETE_NO_PARENT);
}
Task parentTask = getTask(task.getParentTaskId());
if (parentTask == null) {
throw exception(TASK_SIGN_DELETE_NO_PARENT);
}
if (BpmTaskSignTypeEnum.of(parentTask.getScopeType()) == null) {
throw exception(TASK_SIGN_DELETE_NO_PARENT);
}
return task;
}
首先校验任务是否存在;然后校验该任务是否是个子任务,因为只有加签的任务才能被减签而我们当时创建加签任务的时候是通过创建子任务的时候来进行加签的;所有此处的判断直接判断该任务是否有父任务即可。并且进行判断父任务的类型是否属于加签的。最后返回该任务。
校验任务中是否有减签的人
AdminUserRespDTO cancelUser = null;
if (StrUtil.isNotBlank(task.getAssignee())) {
cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee()));
}
if (cancelUser == null && StrUtil.isNotBlank(task.getOwner())) {
cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner()));
}
Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误");
取消并删除子任务
获取所有的子任务
private List<Task> getAllChildTaskList(Task parentTask) {
List<Task> result = new ArrayList<>();
// 1. 递归获取子级
Stack<Task> stack = new Stack<>();
stack.push(parentTask);
// 2. 递归遍历
for (int i = 0; i < Short.MAX_VALUE; i++) {
if (stack.isEmpty()) {
break;
}
// 2.1 获取子任务们
Task task = stack.pop();
List<Task> childTaskList = getTaskListByParentTaskId(task.getId());
// 2.2 如果非空,则添加到 stack 进一步递归
if (CollUtil.isNotEmpty(childTaskList)) {
stack.addAll(childTaskList);
result.addAll(childTaskList);
}
}
return result;
}
更新子任务的状态为已取消并删除子任务
// 2.2 更新子任务为已取消
String cancelReason = StrUtil.format("任务被取消,原因:由于[{}]操作[减签],", cancelUser.getNickname());
childTaskList.forEach(childTask -> updateTaskStatusAndReason(childTask.getId(), BpmTaskStatusEnum.CANCEL.getStatus(), cancelReason));
// 2.3 删除任务和所有子任务
taskService.deleteTasks(convertList(childTaskList, Task::getId));
处理父任务加签出来的子任务
private void handleParentTaskIfSign(String parentTaskId) {
if (StrUtil.isBlank(parentTaskId)) {
return;
}
// 1.1 判断是否还有子任务。如果没有,就不处理
Long childrenTaskCount = getTaskCountByParentTaskId(parentTaskId);
if (childrenTaskCount > 0) {
return;
}
// 1.2 只处理加签的父任务
Task parentTask = validateTaskExist(parentTaskId);
String scopeType = parentTask.getScopeType();
if (BpmTaskSignTypeEnum.of(scopeType) == null) {
return;
}
// 2. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签
TaskEntityImpl parentTaskImpl = (TaskEntityImpl) parentTask;
parentTaskImpl.setScopeType(null);
taskService.saveTask(parentTaskImpl);
// 3.1 情况一:处理向【向前】加签
if (BpmTaskSignTypeEnum.BEFORE.getType().equals(scopeType)) {
// 3.1.1 owner 重新赋值给父任务的 assignee,这样它就可以被审批
taskService.resolveTask(parentTaskId);
// 3.1.2 更新流程任务 status
updateTaskStatus(parentTaskId, BpmTaskStatusEnum.RUNNING.getStatus());
// 3.2 情况二:处理向【向后】加签
} else if (BpmTaskSignTypeEnum.AFTER.getType().equals(scopeType)) {
// 只有 parentTask 处于 APPROVING 的情况下,才可以继续 complete 完成
// 否则,一个未审批的 parentTask 任务,在加签出来的任务都被减签的情况下,就直接完成审批,这样会存在问题
Integer status = (Integer) parentTask.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS);
if (ObjectUtil.notEqual(status, BpmTaskStatusEnum.APPROVING.getStatus())) {
return;
}
// 3.2.2 完成自己(因为它已经没有子任务,所以也可以完成)
updateTaskStatus(parentTaskId, BpmTaskStatusEnum.APPROVE.getStatus());
taskService.complete(parentTaskId);
}
// 4. 递归处理父任务
handleParentTaskIfSign(parentTask.getParentTaskId());
}
后续再进行更新...