package jnpf.dmsService;
|
|
import jnpf.audit.sdk.annotation.AuditLog;
|
import jnpf.dmsEntity.storage.approval.DmsDisableOccupancy;
|
import jnpf.dmsMapper.DmsDisableApplicationMapper;
|
import jnpf.exception.DataException;
|
import jnpf.dmsEntity.storage.form.DmsDisableSubmitValidationForm;
|
import jnpf.flowable.WorkFlowApi;
|
import jnpf.flowable.entity.TaskEntity;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.util.HashSet;
|
import java.util.List;
|
import java.util.Objects;
|
import java.util.Set;
|
|
/** Workflow-event side effect only; native forms still own application persistence. */
|
@Service
|
@RequiredArgsConstructor
|
public class DmsDisableOccupancyService {
|
private static final Set<Integer> RELEASED = Set.of(3, 4, 7, 9);
|
private final DmsDisableApplicationMapper mapper;
|
private final WorkFlowApi workflow;
|
@Value("${dms.disable-occupancy.enabled:false}")
|
private boolean enabled;
|
|
@Transactional(rollbackFor = Exception.class)
|
@AuditLog(action = "DMS_SYNC_DISABLE_OCCUPANCY", bizCodeExpr = "#taskId")
|
public boolean onEvent(String tenantId, String flowId, String taskId, String operation, String eventType) {
|
DmsApprovedDisableService.requireOperation(operation);
|
if (!Set.of("start", "end", "back", "reject", "recall").contains(eventType))
|
throw new DataException("不支持的文件占用流程事件");
|
if (!enabled && !"end".equals(eventType)) throw new DataException("文件占用登记尚未启用,需先完成技术迁移及流程事件配置");
|
TaskEntity task = workflow.getInfoSubmit(taskId);
|
if (task == null || !taskId.equals(task.getId()) || task.getStatus() == null
|
|| (!flowId.equals(task.getFlowId()) && !flowId.equals(task.getTemplateId())))
|
throw new DataException("文件占用事件与真实工作流任务不匹配");
|
DmsDisableOccupancy application = mapper.application(tenantId, taskId, operation);
|
if (application == null || (!Objects.equals(application.getFlowId(), task.getFlowId())
|
&& !Objects.equals(application.getFlowId(), task.getTemplateId()))
|
|| !Objects.equals(application.getFlowState(), task.getStatus()))
|
throw new DataException("文件占用事件与原生申请归属或流程状态不匹配");
|
if (RELEASED.contains(task.getStatus()) && task.getEndTime() != null) {
|
if (enabled) mapper.releaseTask(tenantId, taskId, operation);
|
return false;
|
}
|
if ("end".equals(eventType)) return task.getStatus() == 2 && task.getEndTime() != null;
|
// Returned or recalled but unfinished workflows keep their existing snapshot.
|
if (!"start".equals(eventType) || !Set.of(1, 5, 6, 10).contains(task.getStatus())) return false;
|
List<DmsDisableOccupancy> rows = mapper.applicationFiles(tenantId, application.getApplicationId(), operation);
|
if (rows.isEmpty()) throw new DataException("原生撤销或失效申请没有主文件明细");
|
Set<String> files = new HashSet<>();
|
for (DmsDisableOccupancy row : rows) {
|
if (row.getFileId() == null || row.getFileId().isBlank() || row.getFolderId() == null || row.getFolderId().isBlank() || !files.add(row.getFileId()))
|
throw new DataException("申请明细重复或缺少有效主文件/专属目录关联");
|
}
|
requireAvailable(tenantId, files.stream().toList(), taskId);
|
// One local transaction replaces this task's snapshot; no cross-workflow exclusive lock.
|
mapper.releaseTask(tenantId, taskId, operation);
|
for (DmsDisableOccupancy row : rows) {
|
row.setTenantId(tenantId);
|
row.setOperation(operation);
|
row.setApplicationId(application.getApplicationId());
|
row.setFlowId(task.getFlowId());
|
row.setTaskId(taskId);
|
mapper.occupy(row);
|
}
|
return false;
|
}
|
public void validateSubmission(String tenantId, String userId, String operation, DmsDisableSubmitValidationForm form) {
|
DmsApprovedDisableService.requireOperation(operation);
|
if (!enabled) throw new DataException("文件占用登记尚未启用,不能提交撤销或失效申请");
|
List<String> files = form.getFileIds();
|
if (files == null || files.isEmpty() || files.stream().anyMatch(id -> id == null || id.isBlank())
|
|| new HashSet<>(files).size() != files.size())
|
throw new DataException("请至少选择一个主文件,同一文件不能重复申请");
|
String ownTask = null;
|
if (form.getTaskId() != null && !form.getTaskId().isBlank()) {
|
TaskEntity task = workflow.getInfoSubmit(form.getTaskId());
|
DmsDisableOccupancy application = mapper.application(tenantId, form.getTaskId(), operation);
|
if (task == null || !form.getTaskId().equals(task.getId()) || application == null
|
|| (!form.getFlowId().equals(task.getFlowId()) && !form.getFlowId().equals(task.getTemplateId()))
|
|| (!Objects.equals(application.getFlowId(), task.getFlowId()) && !Objects.equals(application.getFlowId(), task.getTemplateId()))
|
|| task.getStatus() == null || !Set.of(0,1,5,6,8,9,10).contains(task.getStatus()) || task.getEndTime() != null)
|
throw new DataException("仅可沿用本人未结束的原申请,不能排除其他申请的占用");
|
if (Set.of(0,8,9).contains(task.getStatus())) {
|
if (userId == null || userId.isBlank() || !Objects.equals(userId, application.getCreatorUserId()))
|
throw new DataException("仅可沿用本人未结束的原申请");
|
} else {
|
// Native beforeSubmit is also invoked for approval. Only an unchanged
|
// persisted file selection may reuse an in-progress task's snapshot.
|
Set<String> persisted = new HashSet<>();
|
for (DmsDisableOccupancy row : mapper.applicationFiles(tenantId,application.getApplicationId(),operation))
|
persisted.add(row.getFileId());
|
if (!persisted.equals(new HashSet<>(files)))
|
throw new DataException("审批中的文件明细与原申请不一致,不能变更占用范围");
|
}
|
ownTask = task.getId();
|
}
|
requireAvailable(tenantId, files, ownTask);
|
}
|
|
private void requireAvailable(String tenantId, List<String> files, String ownTask) {
|
if (mapper.selectedFiles(tenantId, files).size() != files.size())
|
throw new DataException("所选文件已停用、不是有效主文件或缺少专属目录,请重新选择");
|
if (mapper.conflictingFiles(tenantId, files, ownTask) > 0)
|
throw new DataException("所选文件已有未结束的撤销或失效申请,不能重复提交");
|
}
|
|
}
|