刘光辉
4 小时以前 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
package jnpf.dmsService;
 
import jnpf.audit.sdk.annotation.AuditLog;
import jnpf.base.ActionResult;
import jnpf.dmsEntity.center.*;
import jnpf.dmsEntity.storage.approval.DmsDisableRequest;
import jnpf.dmsEntity.storage.expiry.DmsFileExpiryResource;
import jnpf.dmsMapper.*;
import jnpf.dmsService.center.DmsCenterDisableService;
import jnpf.exception.DataException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
 
/** One item, one transaction. No workflow/storage/search RPC while holding locks. */
@Service
@RequiredArgsConstructor
public class DmsApprovedRevocationExecutor {
    private final DmsRevocationMapper mapper;
    private final DmsCenterDisableService center;
    private final DmsFileExpiryProjectionMapper resources;
    private final DmsFileExpiryMapper cleanup;
    private final DmsDisableApplicationMapper occupancies;
    private final DmsBusinessLifecycleGuard businessOccupancy;
 
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @AuditLog(action = "DMS_APPLY_APPROVED_REVOCATION", bizCodeExpr = "#command.requestId")
    public ActionResult<Void> execute(DmsCenterDisableCommand command) {
        if (command == null || command.getTenantId() == null || command.getRequestId() == null
                || command.getMainDocumentId() == null || command.getExpectedMainVersionId() == null
                || command.getActorId() == null || command.getEffectiveAt() == null
                || command.getLeaseToken() == null || !"yichexiao".equals(command.getReason()))
            throw new DataException("撤销执行参数无效或操作类型不受支持");
        DmsDisableRequest row = mapper.lockRequest(command);
        if (row == null || !"yichexiao".equals(row.getOperation()) || !Objects.equals(row.getDocumentId(), command.getMainDocumentId())
                || !Objects.equals(row.getFileVersionId(), command.getExpectedMainVersionId())
                || !Objects.equals(row.getActorId(), command.getActorId())
                || row.getScheduledAt() == null || row.getScheduledAt().getTime() != command.getEffectiveAt().getTime())
            throw new DataException("撤销请求与已批准登记快照不一致");
        if ("APPLIED".equals(row.getStatus())) return ActionResult.success("文件撤销已完成");
        if (!"WAITING".equals(row.getStatus()))
            throw new DataException("遗留中心执行状态需核对后补偿,不能直接认定撤销成功");
        if (!mapper.validLease(row, command.getLeaseToken()) || !mapper.approvedSource(row))
            throw new DataException("撤销任务租约、执行日期、审批来源或占用已变化");
        var businessReceipts=businessOccupancy.requireExecution(row.getTenantId(),row.getTaskId(),row.getApplicationId(),"REVOCATION",List.of(row.getFileId()));
        var discovered=businessOccupancy.isEnabled() ? mapper.currentTargets(command) : null;
        if(discovered!=null) businessOccupancy.guardVersions(row.getTenantId(),row.getTaskId(),
                discovered.stream().map(t->t.getFileVersionId().toString()).toList());
        Date at = mapper.executionTime();
        if (!center.alreadyIneffective(command, row, at)) {
            List<DmsInvalidationTarget> targets = center.revoke(command, at);
            if(discovered!=null && !new HashSet<>(discovered.stream().map(DmsInvalidationTarget::getFileVersionId).toList())
                    .equals(new HashSet<>(targets.stream().map(DmsInvalidationTarget::getFileVersionId).toList())))
                throw new DataException("执行目录成员已变化,请重试");
            for (DmsInvalidationTarget target : targets) {
                if (resources.hasPendingProjection(row.getTenantId(), target.getFileVersionId()))
                    throw new DataException("批准版本尚未完成业务回写");
                List<DmsFileExpiryResource> matches = resources.lockResources(row.getTenantId(), target.getFileVersionId());
                if (matches.size() != 1) throw new DataException("撤销版本缺少唯一的当前业务资源映射");
                DmsFileExpiryResource resource = matches.get(0);
                String version = target.getFileVersionId().toString();
                if (!version.equals(resource.getCenterVersionId()) || !version.equals(resource.getVersionCenterId())
                        || !("effective".equals(resource.getBizStatus())
                            || ("disabled".equals(resource.getBizStatus()) && "yidaoqi".equals(resource.getDisabledSource())
                                && target.getEffectiveTo() != null && !target.getEffectiveTo().after(at)))
                        || (target.getDocumentId().equals(row.getDocumentId())
                            && (!row.getFileId().equals(resource.getId())
                                || !row.getBusinessVersionId().equals(resource.getCurrentVersionId()))))
                    throw new DataException("撤销业务资源版本或状态已变化");
                if (mapper.disableResource(row, resource, at) != 1) throw new DataException("撤销业务回写失败");
                if (mapper.revokeBusinessVersion(row, resource, at) != 1) throw new DataException("撤销业务版本状态已变化");
                Date validityEnd = target.getEffectiveTo() != null && target.getEffectiveTo().before(at)
                        ? target.getEffectiveTo() : at;
                resources.closeRelations(row.getTenantId(), resource.getId(), validityEnd, row.getActorId());
                cleanup.enqueueCleanup(row.getTenantId(), target.getFileVersionId());
            }
        }
        if (mapper.recordExecution(row, at) != 1) throw new DataException("原生撤销明细回写失败");
        if (occupancies.releaseFile(row.getTenantId(), row.getTaskId(), row.getOperation(), row.getFileId()) != 1)
            throw new DataException("撤销申请占用已变化");
        if (mapper.complete(row, at, command.getLeaseToken()) != 1)
            throw new DataException("撤销执行租约已过期,撤回本次变更后重试");
        businessOccupancy.completeExecution(businessReceipts);
        return ActionResult.success("文件撤销已完成");
    }
}