package jnpf.dmsService; import jnpf.audit.sdk.annotation.AuditLog; import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity; import jnpf.dmsEntity.storage.form.DmsFileLifecycleUpdateForm; import jnpf.dmsEntity.storage.vo.DmsFileLifecycleUpdateVO; import jnpf.dmsIntegration.audit.DmsVersionStateAuditRow; import jnpf.dmsMapper.DmsDocumentMapper; import jnpf.dmsMapper.DmsFileVersionMapper; import jnpf.dmsMapper.DmsVersionStateMapper; import jnpf.exception.DataException; import jnpf.dmsService.expiry.DmsFileExpiryProjection; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.UUID; @Service @RequiredArgsConstructor public class DmsFileLifecycleService { private static final String EFFECTIVE = "EFFECTIVE"; private static final String EXPIRED = "EXPIRED"; private static final String DEFAULT_EXPIRED_REASON = "文件有效期已到,生命周期自动转为已过期"; private final DmsFileVersionMapper fileVersionMapper; private final DmsDocumentMapper documentMapper; private final DmsVersionStateMapper versionStateMapper; private final DmsFileExpiryProjection projection; private final DmsBusinessLifecycleGuard businessOccupancy; @Transactional(rollbackFor = Exception.class) @AuditLog(action = "UPDATE", label = "同步文件到期状态", bizModule = "DMS", bizType = "DMS_FILE_VERSION", bizCodeExpr = "", bizCodeRequired = false, targetTable = "dms_version_states", targetIdExpr = "#p0.fileVersionId", extraExpr = "{'tenantId': #p0.tenantId, 'lifecycleStatus': #p0.lifecycleStatus, " + "'effectiveFrom': #p0.effectiveFrom, 'effectiveTo': #p0.effectiveTo}") public DmsFileLifecycleUpdateVO updateExpired(DmsFileLifecycleUpdateForm form, String serviceId) { if (form == null || form.getTenantId() == null || form.getTenantId().isBlank() || form.getFileVersionId() == null || form.getLifecycleStatus() == null || serviceId == null || serviceId.isBlank()) { throw new DataException("到期同步缺少租户、版本、状态或操作来源"); } String tenantId = form.getTenantId().trim(); String lifecycleStatus = form.getLifecycleStatus().trim(); if (!EXPIRED.equals(lifecycleStatus)) throw new DataException("到期同步仅支持EXPIRED状态"); if (!businessOccupancy.tryEnterExpiry(tenantId, form.getFileVersionId())) throw new DataException("文件业务占用或版本映射尚未释放,到期同步等待后重试"); DmsFileVersionEntity version = fileVersionMapper.selectByTenantAndId( tenantId, form.getFileVersionId()); if (version == null) { throw new DataException("文件版本不存在:" + form.getFileVersionId()); } if (documentMapper.selectByTenantAndIdForUpdate(tenantId, version.getDocumentId()) == null) { throw new DataException("文件所属文档不存在:" + version.getDocumentId()); } DmsVersionStateAuditRow state = versionStateMapper.selectAuditState( tenantId, form.getFileVersionId()); if (state == null) { throw new DataException("文件生命周期状态不存在:" + form.getFileVersionId()); } Date effectiveFrom = state.getEffectiveFrom(); Date effectiveTo = state.getEffectiveTo(); if (effectiveFrom == null || effectiveTo == null || !effectiveTo.after(effectiveFrom)) { throw new DataException("中心未登记合法的有限有效期,不能自动过期"); } if (form.getEffectiveTo() != null && !sameInstant(effectiveTo, form.getEffectiveTo())) { throw new DataException("到期请求与中心已登记有效期不一致,请重新读取后重试"); } if (EXPIRED.equals(state.getLifecycleStatus())) { projection.apply(tenantId, form.getFileVersionId(), effectiveTo, serviceId); return result(form.getFileVersionId(), effectiveFrom, effectiveTo); } if (!EFFECTIVE.equals(state.getLifecycleStatus())) { throw new DataException("文件当前生命周期状态不允许转为EXPIRED:" + state.getLifecycleStatus()); } String reason = trimToNull(form.getStatusReason()); int updated = versionStateMapper.expire( tenantId, form.getFileVersionId(), reason == null ? DEFAULT_EXPIRED_REASON : reason, serviceId); if (updated != 1) { throw new DataException("文件到期状态同步失败,请重试:" + form.getFileVersionId()); } projection.apply(tenantId, form.getFileVersionId(), state.getEffectiveTo(), serviceId); return result(form.getFileVersionId(), effectiveFrom, effectiveTo); } private DmsFileLifecycleUpdateVO result(UUID fileVersionId, Date effectiveFrom, Date effectiveTo) { DmsFileLifecycleUpdateVO result = new DmsFileLifecycleUpdateVO(); result.setFileVersionId(fileVersionId); result.setLifecycleStatus(EXPIRED); result.setEffectiveFrom(effectiveFrom); result.setEffectiveTo(effectiveTo); return result; } private boolean sameInstant(Date first, Date second) { return first != null && second != null && first.getTime() == second.getTime(); } private String trimToNull(String value) { return value == null || value.trim().isEmpty() ? null : value.trim(); } }