merge: t21 存档确认与归档闭环
This commit is contained in:
@@ -163,6 +163,13 @@ public final class ApprovalConstants {
|
||||
return CATEGORY_NAMES.getOrDefault(category, category);
|
||||
}
|
||||
|
||||
/**
|
||||
* 归档后单据为只读终态:任何写动作统一返回该提示。
|
||||
*/
|
||||
public static String writeBlockedMessage(String status) {
|
||||
return STATUS_ARCHIVED.equals(status) ? "单据已归档,不能修改" : "当前状态不可修改";
|
||||
}
|
||||
|
||||
public static String departmentLeaderRoleCode(Integer organizationId) {
|
||||
return organizationId == null ? null : "dept_leader_" + organizationId;
|
||||
}
|
||||
|
||||
@@ -80,6 +80,25 @@ public class ApprovalTaskController extends BaseController {
|
||||
return success("驳回成功", instanceService.detail(result.getInstanceId(), user));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('approval:instance:approve')")
|
||||
@ApiOperation("存档确认")
|
||||
@PostMapping("/task/{id}/confirm")
|
||||
public ApiResult<ApprovalInstanceVO> confirm(@PathVariable("id") Long id) {
|
||||
User user = getLoginUser();
|
||||
ApprovalTaskService.Result result = taskService.confirm(id, user);
|
||||
return success(result.getWarning() == null ? "存档成功" : result.getWarning(),
|
||||
instanceService.detail(result.getInstanceId(), user));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('approval:instance:archive')")
|
||||
@ApiOperation("归档")
|
||||
@PostMapping("/task/{id}/archive")
|
||||
public ApiResult<ApprovalInstanceVO> archive(@PathVariable("id") Long id) {
|
||||
User user = getLoginUser();
|
||||
ApprovalTaskService.Result result = taskService.archive(id, user);
|
||||
return success("归档成功", instanceService.detail(result.getInstanceId(), user));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('approval:instance:submit')")
|
||||
@ApiOperation("撤回")
|
||||
@PostMapping("/instance/{id}/withdraw")
|
||||
|
||||
@@ -162,9 +162,11 @@ public class ApprovalAttachmentService {
|
||||
}
|
||||
|
||||
private void checkEditable(ApprovalInstance instance, User user) {
|
||||
if (user == null || !instance.getReporterId().equals(user.getUserId())
|
||||
|| !ApprovalConstants.EDITABLE_STATUSES.contains(instance.getStatus())) {
|
||||
throw new BusinessException("当前状态不可修改");
|
||||
if (user == null || !instance.getReporterId().equals(user.getUserId())) {
|
||||
throw new BusinessException("无权操作该单据");
|
||||
}
|
||||
if (!ApprovalConstants.EDITABLE_STATUSES.contains(instance.getStatus())) {
|
||||
throw new BusinessException(ApprovalConstants.writeBlockedMessage(instance.getStatus()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ public class ApprovalInstanceService {
|
||||
throw new BusinessException("无权操作该单据");
|
||||
}
|
||||
if (!ApprovalConstants.EDITABLE_STATUSES.contains(instance.getStatus())) {
|
||||
throw new BusinessException("当前状态不可修改");
|
||||
throw new BusinessException(ApprovalConstants.writeBlockedMessage(instance.getStatus()));
|
||||
}
|
||||
ApprovalCompletionForm form = completionForm(instance.getId());
|
||||
if (form == null) {
|
||||
|
||||
@@ -77,6 +77,45 @@ public class ApprovalTaskService {
|
||||
return new Result(instance.getId(), warning);
|
||||
}
|
||||
|
||||
/**
|
||||
* 存档确认:CONFIRM 任务只能确认(无意见),同节点同轮全部完成后实例进入审批完成,
|
||||
* 并激活归档节点;归档节点缺配时实例停在审批中并提示管理员补配置。
|
||||
*/
|
||||
public Result confirm(Long taskId, User user) {
|
||||
ApprovalTask task = requireTask(taskId, user);
|
||||
if (!ApprovalConstants.NODE_CONFIRM.equals(task.getNodeType())) {
|
||||
throw new BusinessException("当前任务不支持存档确认");
|
||||
}
|
||||
ApprovalInstance instance = instanceMapper.selectById(task.getInstanceId());
|
||||
if (instance == null) {
|
||||
throw new BusinessException("单据不存在");
|
||||
}
|
||||
ensureNotArchived(instance);
|
||||
ApprovalNode next = engineService.nextNode(instance, task.getNodeKey());
|
||||
List<ApprovalApprover> approvers =
|
||||
next == null ? Collections.emptyList() : resolveApprovers(instance, next);
|
||||
|
||||
String warning = inTransaction(() -> doConfirm(taskId, task, user, next, approvers));
|
||||
return new Result(instance.getId(), warning);
|
||||
}
|
||||
|
||||
/**
|
||||
* 归档:ARCHIVE 任务或签,处理后取消同节点其余待办,实例进入只读终态。
|
||||
*/
|
||||
public Result archive(Long taskId, User user) {
|
||||
ApprovalTask task = requireTask(taskId, user);
|
||||
if (!ApprovalConstants.NODE_ARCHIVE.equals(task.getNodeType())) {
|
||||
throw new BusinessException("当前任务不支持归档");
|
||||
}
|
||||
ApprovalInstance instance = instanceMapper.selectById(task.getInstanceId());
|
||||
if (instance == null) {
|
||||
throw new BusinessException("单据不存在");
|
||||
}
|
||||
ensureNotArchived(instance);
|
||||
inTransaction(() -> doArchive(taskId, task, user));
|
||||
return new Result(instance.getId(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驳回:意见必填,同轮待办全部取消,实例回到报送人。
|
||||
*/
|
||||
@@ -103,6 +142,9 @@ public class ApprovalTaskService {
|
||||
if (user == null || !instance.getReporterId().equals(user.getUserId())) {
|
||||
throw new BusinessException("无权操作该单据");
|
||||
}
|
||||
if (ApprovalConstants.STATUS_ARCHIVED.equals(instance.getStatus())) {
|
||||
throw new BusinessException("单据已归档,不能修改");
|
||||
}
|
||||
if (!ApprovalConstants.STATUS_PENDING.equals(instance.getStatus())) {
|
||||
throw new BusinessException("当前状态不可撤回");
|
||||
}
|
||||
@@ -155,6 +197,67 @@ public class ApprovalTaskService {
|
||||
return created == 0 ? "当前节点缺少审批人,请联系管理员补配置" : null;
|
||||
}
|
||||
|
||||
private String doConfirm(Long taskId, ApprovalTask task, User user,
|
||||
ApprovalNode next, List<ApprovalApprover> approvers) {
|
||||
ApprovalInstance locked = engineService.lockInstance(task.getInstanceId());
|
||||
ensureNotArchived(locked);
|
||||
ensureTaskHandleable(task, locked);
|
||||
if (updatePendingTask(taskId, ApprovalConstants.TASK_DONE, null) == 0) {
|
||||
throw new BusinessException("任务已处理");
|
||||
}
|
||||
engineService.addRecord(locked, taskId, task.getNodeKey(), user,
|
||||
ApprovalConstants.ACTION_CONFIRM, null);
|
||||
Integer remaining = taskMapper.selectCount(new LambdaQueryWrapper<ApprovalTask>()
|
||||
.eq(ApprovalTask::getInstanceId, locked.getId())
|
||||
.eq(ApprovalTask::getRound, locked.getRound())
|
||||
.eq(ApprovalTask::getNodeKey, task.getNodeKey())
|
||||
.eq(ApprovalTask::getStatus, ApprovalConstants.TASK_PENDING));
|
||||
if (remaining != null && remaining > 0) {
|
||||
return null;
|
||||
}
|
||||
if (next == null) {
|
||||
return "当前节点缺少审批人,请联系管理员补配置";
|
||||
}
|
||||
int created = engineService.moveToNode(locked, next, locked.getRound(), approvers);
|
||||
if (created == 0) {
|
||||
return "当前节点缺少审批人,请联系管理员补配置";
|
||||
}
|
||||
int rows = instanceMapper.update(null, new UpdateWrapper<ApprovalInstance>()
|
||||
.eq("id", locked.getId())
|
||||
.eq("status", ApprovalConstants.STATUS_PENDING)
|
||||
.set("status", ApprovalConstants.STATUS_APPROVED)
|
||||
.set("approve_time", LocalDateTime.now()));
|
||||
if (rows == 0) {
|
||||
throw new BusinessException("单据状态已变化,请刷新后重试");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void doArchive(Long taskId, ApprovalTask task, User user) {
|
||||
ApprovalInstance locked = engineService.lockInstance(task.getInstanceId());
|
||||
ensureNotArchived(locked);
|
||||
if (!ApprovalConstants.STATUS_APPROVED.equals(locked.getStatus())) {
|
||||
throw new BusinessException("单据状态已变化,请刷新后重试");
|
||||
}
|
||||
ensureTaskCurrent(task, locked);
|
||||
if (updatePendingTask(taskId, ApprovalConstants.TASK_DONE, null) == 0) {
|
||||
throw new BusinessException("任务已处理");
|
||||
}
|
||||
engineService.cancelPendingTasks(locked.getId(), locked.getRound(), taskId);
|
||||
engineService.addRecord(locked, taskId, task.getNodeKey(), user,
|
||||
ApprovalConstants.ACTION_ARCHIVE, null);
|
||||
int rows = instanceMapper.update(null, new UpdateWrapper<ApprovalInstance>()
|
||||
.eq("id", locked.getId())
|
||||
.eq("status", ApprovalConstants.STATUS_APPROVED)
|
||||
.set("status", ApprovalConstants.STATUS_ARCHIVED)
|
||||
.set("archive_time", LocalDateTime.now())
|
||||
.set("archivist_id", user.getUserId())
|
||||
.set("archivist_name", displayName(user)));
|
||||
if (rows == 0) {
|
||||
throw new BusinessException("单据状态已变化,请刷新后重试");
|
||||
}
|
||||
}
|
||||
|
||||
private void doReject(Long taskId, ApprovalTask task, String opinion, User user) {
|
||||
ApprovalInstance locked = engineService.lockInstance(task.getInstanceId());
|
||||
ensureTaskHandleable(task, locked);
|
||||
@@ -254,12 +357,22 @@ public class ApprovalTaskService {
|
||||
if (!ApprovalConstants.STATUS_PENDING.equals(instance.getStatus())) {
|
||||
throw new BusinessException("单据状态已变化,请刷新后重试");
|
||||
}
|
||||
ensureTaskCurrent(task, instance);
|
||||
}
|
||||
|
||||
private void ensureTaskCurrent(ApprovalTask task, ApprovalInstance instance) {
|
||||
if (!task.getRound().equals(instance.getRound())
|
||||
|| !task.getNodeKey().equals(instance.getCurrentNodeKey())) {
|
||||
throw new BusinessException("任务已处理");
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureNotArchived(ApprovalInstance instance) {
|
||||
if (ApprovalConstants.STATUS_ARCHIVED.equals(instance.getStatus())) {
|
||||
throw new BusinessException("单据已归档,不能修改");
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureNoHandledTask(ApprovalInstance instance) {
|
||||
Integer handled = taskMapper.selectCount(new LambdaQueryWrapper<ApprovalTask>()
|
||||
.eq(ApprovalTask::getInstanceId, instance.getId())
|
||||
@@ -364,6 +477,16 @@ public class ApprovalTaskService {
|
||||
return user.getUsername();
|
||||
}
|
||||
|
||||
private String displayName(User user) {
|
||||
if (StrUtil.isNotBlank(user.getRealName())) {
|
||||
return user.getRealName();
|
||||
}
|
||||
if (StrUtil.isNotBlank(user.getNickname())) {
|
||||
return user.getNickname();
|
||||
}
|
||||
return user.getUsername();
|
||||
}
|
||||
|
||||
private String normalizeOpinion(String opinion) {
|
||||
if (opinion == null) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user