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<DmsWenjianXinzengShenheEntity> 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<DmsWenjianXiudingShenheEntity> 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) + ")";
|
}
|
}
|