package jnpf.dmsService.impl; import jnpf.base.UserInfo; import jnpf.dmsEntity.DmsWenjianBanbenKongzhiEntity; import jnpf.dmsEntity.DmsWenjianXinzengGuanliEntity; import jnpf.dmsEntity.DmsWenjianXinzengShenheEntity; import jnpf.dmsEntity.DmsWenjianXiudingShenheEntity; import jnpf.dmsEntity.DmsWenjianXiudingShenqingEntity; import jnpf.dmsEntity.wenjianbianhao.DmsFlowEventType; import jnpf.dmsMapper.DmsWenjianBanbenKongzhiMapper; import jnpf.dmsMapper.DmsWenjianXinzengGuanliMapper; import jnpf.dmsMapper.DmsWenjianXinzengShenheMapper; import jnpf.dmsMapper.DmsWenjianXiudingShenheMapper; import jnpf.dmsMapper.DmsWenjianXiudingShenqingMapper; import jnpf.dmsPermission.DmsCurrentIdentity; import jnpf.dmsService.DmsWenjianBanbenService; import jnpf.exception.DataException; import jnpf.util.RandomUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.List; import java.util.Objects; @Slf4j @Service @RequiredArgsConstructor public class DmsWenjianBanbenServiceImpl implements DmsWenjianBanbenService { private static final int RUNNING = 1; private static final int PASSED = 2; private static final int EXCEPTION = 10; private static final String EFFECTIVE = "effective"; private static final String NEW = "xinzeng"; private static final String REVISION = "xiuding"; private static final String NEW_SOURCE = "xinding"; private static final String UPGRADE = "shengji"; private static final String UNCHANGED = "wubianhua"; private final DmsCurrentIdentity identity; private final DmsWenjianBanbenKongzhiMapper controlMapper; private final DmsWenjianXinzengGuanliMapper newRequestMapper; private final DmsWenjianXinzengShenheMapper newAuditMapper; private final DmsWenjianXiudingShenqingMapper revisionRequestMapper; private final DmsWenjianXiudingShenheMapper revisionAuditMapper; @Override @Transactional(rollbackFor = Exception.class) public void syncNewAuditFlow(String flowId, String taskId, Integer flowState, DmsFlowEventType eventType) throws DataException { UserInfo user = identity.requireUser(); String tenantId = identity.tenantId(user); String resolvedFlowId = requireText(flowId, "流程ID不能为空"); String resolvedTaskId = requireText(taskId, "流程任务ID不能为空"); requireEvent(eventType); DmsWenjianXinzengShenheEntity audit = uniqueNewAudit( newAuditMapper.selectByFlowForUpdate(tenantId, resolvedFlowId, resolvedTaskId)); verifyPersistedState(audit.getFlowState(), flowState); if (!requiresVersionCheck(flowState)) { return; } if (hasCompleteNewResult(audit)) { return; } String requestId = requireText(audit.getShenqingdanId(), "新增审核单未关联新增申请"); DmsWenjianXinzengGuanliEntity request = newRequestMapper.selectByIdForUpdate(tenantId, requestId); validateNewRequest(request); DmsWenjianBanbenKongzhiEntity control = controlMapper.selectByFileForUpdate(tenantId, request.getId()); if (control != null) { if (NEW.equals(control.getZuihouShengxiaoLeixing()) && audit.getId().equals(control.getZuihouShengxiaoDanjuId())) { if (flowState == PASSED) { writeNewAuditResult(audit, new Date()); } return; } throw new DataException("该文件已经存在正式版本,不能重复初始化"); } if (flowState != PASSED) { return; } Date now = new Date(); DmsWenjianBanbenKongzhiEntity created = new DmsWenjianBanbenKongzhiEntity(); created.setId(RandomUtil.uuId()); created.setTenantId(tenantId); created.setWenjianId(request.getId()); created.setBanbenXuhao(0); created.setBiangengXuhao(0L); created.setZuihouShengxiaoLeixing(NEW); created.setZuihouShengxiaoDanjuId(audit.getId()); created.setBizStatus(EFFECTIVE); created.setCreatorUserId(user.getUserId()); created.setCreatorTime(now); requireSingleUpdate(controlMapper.insertControl(created), "初始化文件正式版本失败"); writeNewAuditResult(audit, now); log.info("文件新增审核生成正式版本,auditId={}, wenjianId={}, version=D(00)", audit.getId(), request.getId()); } @Override @Transactional(rollbackFor = Exception.class) public void syncRevisionAuditFlow(String flowId, String taskId, Integer flowState, DmsFlowEventType eventType) throws DataException { UserInfo user = identity.requireUser(); String tenantId = identity.tenantId(user); String resolvedFlowId = requireText(flowId, "流程ID不能为空"); String resolvedTaskId = requireText(taskId, "流程任务ID不能为空"); requireEvent(eventType); DmsWenjianXiudingShenheEntity audit = uniqueRevisionAudit( revisionAuditMapper.selectByFlowForUpdate( tenantId, resolvedFlowId, resolvedTaskId)); verifyPersistedState(audit.getFlowState(), flowState); if (!requiresVersionCheck(flowState)) { return; } if (hasCompleteRevisionResult(audit)) { return; } String requestId = requireText(audit.getXiudingShenqingId(), "修订审核单未关联修订申请"); DmsWenjianXiudingShenqingEntity request = revisionRequestMapper.selectByIdForUpdate(tenantId, requestId); validateRevisionRequest(request); DmsWenjianBanbenKongzhiEntity control = controlMapper.selectByFileForUpdate( tenantId, request.getWenjianId()); validateControl(control); verifySourceSnapshot(request, control); validateChangeType(audit.getBiangengFangshi()); if (flowState != PASSED) { return; } int expectedVersion = control.getBanbenXuhao(); long expectedChange = control.getBiangengXuhao(); int effectiveVersion = calculateEffectiveVersion( expectedVersion, audit.getBiangengFangshi()); long effectiveChange; try { effectiveChange = Math.addExact(expectedChange, 1L); } catch (ArithmeticException exception) { throw new DataException("文件变更序号已达到上限"); } Date now = new Date(); control.setBanbenXuhao(effectiveVersion); control.setBiangengXuhao(effectiveChange); control.setZuihouShengxiaoLeixing(REVISION); control.setZuihouShengxiaoDanjuId(audit.getId()); control.setBizStatus(EFFECTIVE); control.setLastModifyUserId(user.getUserId()); control.setLastModifyTime(now); requireSingleUpdate(controlMapper.advance( control, expectedVersion, expectedChange), "更新文件正式版本失败"); audit.setShengxiaoBanbenXuhao(effectiveVersion); audit.setShengxiaoBanbenhao(formatVersion(effectiveVersion)); audit.setShengxiaoBiangengXuhao(effectiveChange); audit.setBanbenShengxiaoShijian(now); requireSingleUpdate(revisionAuditMapper.updateEffectiveVersion(audit), "回写修订审核生效版本失败"); log.info("文件修订审核生成正式版本,auditId={}, wenjianId={}, version={}, changeSequence={}", audit.getId(), request.getWenjianId(), audit.getShengxiaoBanbenhao(), effectiveChange); } private void validateNewRequest(DmsWenjianXinzengGuanliEntity request) throws DataException { if (request == null) { throw new DataException("未找到新增审核单关联的新增申请"); } if (!Objects.equals(request.getFlowState(), PASSED)) { throw new DataException("关联的文件新增申请尚未审批通过"); } if (!NEW_SOURCE.equals(request.getXinxiuding())) { throw new DataException("关联记录不是文件新订申请"); } if (!Objects.equals(request.getBanbenXuhao(), 0) || !formatVersion(0).equals(request.getBanbenhao())) { throw new DataException("文件新订申请的初始版本必须为D(00)"); } } private void validateRevisionRequest(DmsWenjianXiudingShenqingEntity request) throws DataException { if (request == null) { throw new DataException("未找到修订审核单关联的修订申请"); } if (!Objects.equals(request.getFlowState(), PASSED)) { throw new DataException("关联的文件修订申请尚未审批通过"); } requireText(request.getWenjianId(), "修订申请未关联来源文件"); if (request.getBanbenXuhao() == null || request.getBanbenXuhao() < 0) { throw new DataException("修订申请来源版本序号无效"); } if (request.getYuanBiangengXuhao() == null || request.getYuanBiangengXuhao() < 0) { throw new DataException("修订申请来源变更序号无效"); } if (!formatVersion(request.getBanbenXuhao()).equals(request.getBanbenhao())) { throw new DataException("修订申请来源版本号与版本序号不一致"); } } private void validateControl(DmsWenjianBanbenKongzhiEntity control) throws DataException { if (control == null) { throw new DataException("来源文件尚未建立正式版本"); } if (!EFFECTIVE.equals(control.getBizStatus())) { throw new DataException("来源文件当前不是有效状态"); } if (control.getBanbenXuhao() == null || control.getBanbenXuhao() < 0 || control.getBiangengXuhao() == null || control.getBiangengXuhao() < 0) { throw new DataException("来源文件版本控制数据无效"); } } private void verifySourceSnapshot(DmsWenjianXiudingShenqingEntity request, DmsWenjianBanbenKongzhiEntity control) throws DataException { if (!Objects.equals(request.getBanbenXuhao(), control.getBanbenXuhao()) || !Objects.equals(request.getYuanBiangengXuhao(), control.getBiangengXuhao())) { throw new DataException("来源文件已有其他修订生效,请重新发起修订申请"); } } private int calculateEffectiveVersion(int currentVersion, String changeType) throws DataException { if (UNCHANGED.equals(changeType)) { return currentVersion; } try { return Math.addExact(currentVersion, 1); } catch (ArithmeticException exception) { throw new DataException("文件版本序号已达到上限"); } } private void validateChangeType(String changeType) throws DataException { if (!UPGRADE.equals(changeType) && !UNCHANGED.equals(changeType)) { throw new DataException("修订审核单的变更方式无效"); } } private void writeNewAuditResult(DmsWenjianXinzengShenheEntity audit, Date now) throws DataException { audit.setShengxiaoBanbenXuhao(0); audit.setShengxiaoBanbenhao(formatVersion(0)); audit.setShengxiaoBiangengXuhao(0L); audit.setBanbenShengxiaoShijian(now); requireSingleUpdate(newAuditMapper.updateEffectiveVersion(audit), "回写新增审核生效版本失败"); } private boolean hasCompleteNewResult(DmsWenjianXinzengShenheEntity audit) throws DataException { boolean any = audit.getShengxiaoBanbenXuhao() != null || audit.getShengxiaoBanbenhao() != null || audit.getShengxiaoBiangengXuhao() != null || audit.getBanbenShengxiaoShijian() != null; if (!any) { return false; } boolean complete = Objects.equals(audit.getShengxiaoBanbenXuhao(), 0) && formatVersion(0).equals(audit.getShengxiaoBanbenhao()) && Objects.equals(audit.getShengxiaoBiangengXuhao(), 0L) && audit.getBanbenShengxiaoShijian() != null; if (!complete) { throw new DataException("新增审核单的生效版本结果不完整"); } return true; } private boolean hasCompleteRevisionResult(DmsWenjianXiudingShenheEntity audit) throws DataException { boolean any = audit.getShengxiaoBanbenXuhao() != null || audit.getShengxiaoBanbenhao() != null || audit.getShengxiaoBiangengXuhao() != null || audit.getBanbenShengxiaoShijian() != null; if (!any) { return false; } boolean complete = audit.getShengxiaoBanbenXuhao() != null && audit.getShengxiaoBanbenXuhao() >= 0 && formatVersion(audit.getShengxiaoBanbenXuhao()) .equals(audit.getShengxiaoBanbenhao()) && audit.getShengxiaoBiangengXuhao() != null && audit.getShengxiaoBiangengXuhao() >= 0 && audit.getBanbenShengxiaoShijian() != null; if (!complete) { throw new DataException("修订审核单的生效版本结果不完整"); } return true; } private boolean requiresVersionCheck(Integer flowState) throws DataException { if (flowState == null) { throw new DataException("工作流状态不能为空"); } if (flowState == EXCEPTION) { throw new DataException("文件审核流程处于异常状态,请修复流程后重试"); } return flowState == RUNNING || flowState == PASSED; } private void verifyPersistedState(Integer persistedState, Integer workflowState) throws DataException { if (!Objects.equals(persistedState, workflowState)) { throw new DataException("流程状态尚未同步完成:表单状态=" + persistedState + ",任务状态=" + workflowState + ",请稍后重试"); } } private DmsWenjianXinzengShenheEntity uniqueNewAudit( List rows) throws DataException { if (rows == null || rows.isEmpty()) { throw new DataException("未找到文件新增审核流程关联记录"); } if (rows.size() > 1) { throw new DataException("多个文件新增审核单关联同一流程任务"); } return rows.get(0); } private DmsWenjianXiudingShenheEntity uniqueRevisionAudit( List rows) throws DataException { if (rows == null || rows.isEmpty()) { throw new DataException("未找到文件修订审核流程关联记录"); } if (rows.size() > 1) { throw new DataException("多个文件修订审核单关联同一流程任务"); } return rows.get(0); } private void requireEvent(DmsFlowEventType eventType) throws DataException { if (eventType == null) { throw new DataException("流程事件类型不能为空"); } } private String requireText(String value, String message) throws DataException { if (value == null || value.trim().isEmpty()) { throw new DataException(message); } return value.trim(); } private void requireSingleUpdate(int affected, String message) throws DataException { if (affected != 1) { throw new DataException(message); } } static String formatVersion(int sequence) { String value = Integer.toString(sequence); return "D(" + (value.length() < 2 ? "0" + value : value) + ")"; } }