package jnpf.dmsService.center;
|
|
import jnpf.dmsIntegration.audit.DmsBusinessChangeAudit;
|
import static jnpf.dmsIntegration.audit.DmsBusinessChangeAudit.values;
|
|
import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity;
|
|
import jnpf.dmsEntity.center.DmsCenterActivation;
|
import jnpf.dmsEntity.permission.entity.DmsDocumentEntity;
|
import jnpf.dmsMapper.*;
|
import jnpf.dmsService.search.DmsSearchIndexJobService;
|
import jnpf.exception.DataException;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import java.util.*;
|
|
/** Atomic center state transitions; no native form, workflow API or business queue dependency. */
|
@Service
|
@RequiredArgsConstructor
|
public class DmsCenterActivationService {
|
private final DmsBusinessChangeAudit businessAudit;
|
private final DmsDocumentMapper documents;
|
private final DmsFileVersionMapper versions;
|
private final DmsVersionStateMapper states;
|
private final DmsSearchIndexJobService search;
|
|
@Transactional(rollbackFor = Exception.class)
|
public void activate(String tenantId, String actorId, List<DmsCenterActivation> targets) {
|
if (tenantId == null || tenantId.isBlank() || actorId == null || actorId.isBlank()
|
|| targets == null || targets.isEmpty()) throw new DataException("中心生效请求不完整");
|
Set<UUID> seen = new HashSet<>();
|
for (DmsCenterActivation target : targets) {
|
if (target == null || target.documentId() == null || target.fileVersionId() == null
|
|| !Set.of("CREATE", "REVISE", "REUSE", "RETIRE").contains(target.operation())
|
|| !seen.add(target.documentId())) throw new DataException("中心生效目标无效或重复");
|
}
|
List<DmsCenterActivation> ordered = targets.stream().sorted(Comparator.comparing(t -> t.documentId().toString())).toList();
|
Map<UUID, DmsDocumentEntity> locked = new HashMap<>();
|
for (DmsCenterActivation target : ordered) {
|
DmsDocumentEntity document = documents.selectByTenantAndIdForUpdate(tenantId, target.documentId());
|
if (document == null)
|
throw new DataException("接收文件不存在");
|
locked.put(target.documentId(), document);
|
}
|
for (DmsCenterActivation target : ordered) {
|
if (!"RETIRE".equals(target.operation())) continue;
|
UUID mainId = locked.get(target.documentId()).getMainDocumentId();
|
if (mainId == null || !locked.containsKey(mainId)
|
|| locked.get(mainId).getMainDocumentId() != null
|
|| targets.stream().noneMatch(t -> mainId.equals(t.documentId())
|
&& Set.of("REUSE", "REVISE").contains(t.operation())))
|
throw new DataException("只能将本次修订主文件目录中的记录转入历史");
|
}
|
for (DmsCenterActivation target : ordered) {
|
DmsFileVersionEntity current = versions.selectCurrentEffective(tenantId, target.documentId());
|
if ("RETIRE".equals(target.operation())) {
|
if (current == null || !target.fileVersionId().equals(current.getId())
|
|| !target.fileVersionId().equals(target.baseFileVersionId()))
|
throw new DataException("移除记录已不是原批准的现行版本");
|
var before = states.selectAuditState(tenantId, target.fileVersionId());
|
if (states.retireCurrent(tenantId, target.documentId(), target.fileVersionId(), actorId) != 1)
|
throw new DataException("移除记录转入历史失败");
|
recordState(tenantId, actorId, target.documentId(), target.fileVersionId(), before);
|
continue;
|
}
|
if ("REUSE".equals(target.operation())) {
|
if (current == null || !target.fileVersionId().equals(current.getId()))
|
throw new DataException("沿用版本已不是现行版本");
|
continue;
|
}
|
DmsFileVersionEntity version = versions.selectByTenantAndId(tenantId, target.fileVersionId());
|
if (version == null || !target.documentId().equals(version.getDocumentId()))
|
throw new DataException("生效版本不属于目标文档");
|
if ("REVISE".equals(target.operation())) {
|
if (current == null || !Objects.equals(target.baseFileVersionId(), current.getId()))
|
throw new DataException("修订来源版本已不是现行版本");
|
var before = states.selectAuditState(tenantId, current.getId());
|
if (states.supersedeCurrent(tenantId, target.documentId(), current.getId(),
|
version.getVersionLabel(), actorId) != 1) throw new DataException("现行版本切换失败");
|
recordState(tenantId, actorId, target.documentId(), current.getId(), before);
|
} else if (current != null) throw new DataException("新文件已存在有效版本");
|
var before = states.selectAuditState(tenantId, target.fileVersionId());
|
if (states.activateApproved(tenantId, target.fileVersionId(), actorId) != 1)
|
throw new DataException("批准文件尚未到生效日期或已失效");
|
recordState(tenantId, actorId, target.documentId(), target.fileVersionId(), before);
|
search.enqueueContentUpsert(tenantId, target.documentId(), target.fileVersionId(), target.checksumSha256());
|
}
|
}
|
|
private void recordState(String tenantId, String approvalActorId, UUID documentId, UUID versionId,
|
jnpf.dmsIntegration.audit.DmsVersionStateAuditRow before) {
|
var after = states.selectAuditState(tenantId, versionId);
|
if (before == null || after == null) throw new DataException("文件状态审计快照缺失");
|
businessAudit.record(tenantId, "DMS_VERSION_STATE_CHANGED", "文件版本效力变更",
|
"dms_version_states", versionId.toString(), state(before), state(after), after.getStatusReason(),
|
values("document_id", documentId, "file_version_id", versionId, "approval_actor_id", approvalActorId));
|
}
|
|
private Map<String, Object> state(jnpf.dmsIntegration.audit.DmsVersionStateAuditRow value) {
|
return values("lifecycle_status", value.getLifecycleStatus(), "effective_from", value.getEffectiveFrom(),
|
"effective_to", value.getEffectiveTo(), "status_reason", value.getStatusReason());
|
}
|
}
|