刘光辉
117 分钟以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package jnpf.dmsService;
 
import jnpf.dmsEntity.permission.entity.DmsDocumentEntity;
import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity;
import jnpf.dmsEntity.storage.DmsWorkflowSourceKey;
import jnpf.dmsEntity.storage.enums.DmsWorkflowFileType;
import jnpf.dmsEntity.storage.vo.DmsFileUploadVO;
import jnpf.dmsIntegration.audit.DmsVersionStateAuditRow;
import jnpf.dmsMapper.DmsDocumentMapper;
import jnpf.dmsMapper.DmsFileObjectMapper;
import jnpf.dmsMapper.DmsFileVersionMapper;
import jnpf.dmsMapper.DmsVersionStateMapper;
import jnpf.dmsPermission.DmsPermissionError;
import jnpf.dmsPermission.DmsPermissionException;
import jnpf.dmsService.search.DmsSearchIndexJobService;
import jnpf.exception.DataException;
import jnpf.flowable.WorkFlowApi;
import jnpf.flowable.entity.TaskEntity;
import jnpf.flowable.enums.TaskStatusEnum;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.util.Objects;
 
@Service
@RequiredArgsConstructor
public class DmsWorkflowFileActivationService {
    private static final String SERVICE_ID = "jnpf-file";
 
    private final WorkFlowApi workFlowApi;
    private final DmsFileObjectMapper fileObjectMapper;
    private final DmsDocumentMapper documentMapper;
    private final DmsFileVersionMapper fileVersionMapper;
    private final DmsVersionStateMapper versionStateMapper;
    private final DmsSearchIndexJobService searchIndexJobService;
    private final DmsBusinessLifecycleGuard businessOccupancy;
 
    @Transactional(rollbackFor = Exception.class)
    public DmsFileUploadVO activate(String tenantId, String flowId, String taskId,
                                    DmsWorkflowFileType fileType, String approvedBy) {
        TaskEntity task = requireTask(flowId, taskId);
        if (!TaskStatusEnum.PASSED.getCode().equals(task.getStatus())) {
            throw new DataException("流程任务尚未审核通过,不能激活文件");
        }
        return activateVerified(tenantId, flowId, taskId, fileType, approvedBy);
    }
 
    @Transactional(rollbackFor = Exception.class)
    public DmsFileUploadVO activateVerified(String tenantId, String flowId, String taskId,
                                            DmsWorkflowFileType fileType, String approvedBy) {
        String activationActor = actor(approvedBy);
        String sourceKey = DmsWorkflowSourceKey.of(flowId, taskId, fileType);
        DmsFileUploadVO staged = fileObjectMapper.selectUploadBySource(tenantId, SERVICE_ID, sourceKey);
        if (staged == null || staged.getFileVersionId() == null || staged.getDocumentId() == null) {
            throw new DataException("未找到当前流程任务暂存的文件");
        }
        // Number lock precedes center row locks; no caller task ID can exempt a business chain.
        businessOccupancy.guardStandaloneActivation(tenantId,staged.getFileVersionId());
        DmsDocumentEntity document = documentMapper.selectByTenantAndIdForUpdate(
                tenantId, staged.getDocumentId());
        if (document == null) {
            throw DmsPermissionException.of(DmsPermissionError.RESOURCE_NOT_FOUND, "暂存文件不存在");
        }
        DmsVersionStateAuditRow state = versionStateMapper.selectAuditState(
                tenantId, staged.getFileVersionId());
        if (state != null && "EFFECTIVE".equals(state.getLifecycleStatus())) {
            staged.setLifecycleStatus("EFFECTIVE");
            return staged;
        }
        if (state == null || !"PENDING_APPROVAL".equals(state.getLifecycleStatus())) {
            throw new DataException("暂存文件状态不允许激活");
        }
 
        if (fileType == DmsWorkflowFileType.REVISE) {
            DmsFileVersionEntity current = fileVersionMapper.selectCurrentEffective(
                    tenantId, staged.getDocumentId());
            if (current == null || !Objects.equals(current.getId(), staged.getBaseFileVersionId())) {
                throw DmsPermissionException.of(DmsPermissionError.REVISION_CONFLICT,
                        "待修订版本已不是现行有效版本,请重新发起审批");
            }
            int superseded = versionStateMapper.supersedeCurrent(tenantId, staged.getDocumentId(),
                    current.getId(), staged.getVersionLabel(), activationActor);
            if (superseded != 1) {
                throw DmsPermissionException.of(DmsPermissionError.REVISION_CONFLICT,
                        "现行有效版本已发生变化,请重试");
            }
        } else if (fileVersionMapper.selectCurrentEffective(tenantId, staged.getDocumentId()) != null) {
            throw new DataException("新增文件已经存在有效版本");
        }
 
        if (versionStateMapper.activateWorkflowPending(
                tenantId, staged.getFileVersionId(), flowId, taskId, fileType.name(),
                activationActor) != 1) {
            throw new DataException("工作流文件激活失败,请重试");
        }
        searchIndexJobService.enqueueContentUpsert(tenantId, staged.getDocumentId(),
                staged.getFileVersionId(), staged.getChecksumSha256());
        staged.setLifecycleStatus("EFFECTIVE");
        return staged;
    }
 
    TaskEntity requireTask(String flowId, String taskId) {
        TaskEntity task = workFlowApi.getInfoSubmit(taskId);
        if (task == null || !taskId.equals(task.getId())) {
            throw new DataException("未找到与taskId匹配的流程任务");
        }
        if (!flowId.equals(task.getFlowId()) && !flowId.equals(task.getTemplateId())) {
            throw new DataException("流程任务不属于指定flowID");
        }
        return task;
    }
 
    private String actor(String value) {
        return value == null || value.trim().isEmpty() ? "dms-workflow-activation" : value.trim();
    }
}