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 DmsApprovedInvalidationExecutor {
|
private final DmsInvalidationMapper mapper;
|
private final DmsInvalidationProperties properties;
|
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_INVALIDATION", 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 || !"yishixiao".equals(command.getReason()))
|
throw new DataException("失效执行参数无效或操作类型不受支持");
|
DmsDisableRequest row = mapper.lockRequest(command);
|
if (row == null || !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 (!properties.allows(row.getTenantId(), row.getBatchId()))
|
throw new DataException("该失效批次尚未纳入执行范围");
|
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(),"INVALIDATION",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.invalidate(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())
|
|| (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.invalidateBusinessVersion(row, resource, at) != 1) throw new DataException("失效业务版本状态已变化");
|
resources.closeRelations(row.getTenantId(), resource.getId(), at, 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("文件失效已完成");
|
}
|
}
|