package jnpf.dmsService.impl;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import jnpf.dmsEntity.storage.approval.DmsApprovedItem;
|
import jnpf.dmsEntity.storage.approval.DmsApprovedBatch;
|
import jnpf.base.UserInfo;
|
import jnpf.dmsEntity.DmsWenjianBanbenEntity;
|
import jnpf.dmsEntity.DmsWenjianBianhaoEntity;
|
import jnpf.dmsEntity.DmsWenjianGuanlianMingxiEntity;
|
import jnpf.dmsEntity.DmsWenjianGuanxiEntity;
|
import jnpf.dmsEntity.DmsWenjianXinzengShenheEntity;
|
import jnpf.dmsEntity.DmsWenjianXinzengShenheJiluMingxiEntity;
|
import jnpf.dmsEntity.DmsWenjianXiudingShenheEntity;
|
import jnpf.dmsEntity.DmsWenjianXiudingShenheJiluMingxiEntity;
|
import jnpf.dmsEntity.DmsWenjianXiudingShenqingEntity;
|
import jnpf.dmsEntity.DmsWenjianXiudingShenqingZixiangEntity;
|
import jnpf.dmsEntity.banben.DmsWenjianBanbenJiesuanModel;
|
import jnpf.dmsEntity.banben.vo.DmsWenjianBanbenQueryVO;
|
import jnpf.dmsEntity.banben.vo.DmsWenjianZhongxinBanbenVO;
|
import jnpf.dmsEntity.wenjianbianhao.DmsFlowEventType;
|
import jnpf.dmsMapper.DmsWenjianBanbenMapper;
|
import jnpf.dmsMapper.DmsWenjianBianhaoMapper;
|
import jnpf.dmsMapper.DmsWenjianGuanlianMingxiMapper;
|
import jnpf.dmsMapper.DmsWenjianGuanxiMapper;
|
import jnpf.dmsMapper.DmsWenjianXinzengShenheJiluMingxiMapper;
|
import jnpf.dmsMapper.DmsWenjianXinzengShenheMapper;
|
import jnpf.dmsMapper.DmsWenjianXiudingShenheJiluMingxiMapper;
|
import jnpf.dmsMapper.DmsWenjianXiudingShenheMapper;
|
import jnpf.dmsMapper.DmsWenjianXiudingShenqingMapper;
|
import jnpf.dmsMapper.DmsWenjianXiudingShenqingZixiangMapper;
|
import jnpf.dmsPermission.DmsCurrentIdentity;
|
import jnpf.dmsService.DmsWenjianBanbenService;
|
import jnpf.dmsService.DmsWenjianFenfaService;
|
import jnpf.dmsService.DmsWenjianYewuBanbenService;
|
import jnpf.exception.DataException;
|
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.HashSet;
|
import java.util.List;
|
import java.util.Objects;
|
import java.util.Set;
|
|
@Slf4j
|
@Service
|
@RequiredArgsConstructor
|
public class DmsWenjianBanbenServiceImpl implements DmsWenjianBanbenService {
|
|
private static final ObjectMapper CONTENT_JSON = new ObjectMapper();
|
|
private static final int RUNNING = 1;
|
private static final int PASSED = 2;
|
private static final int EXCEPTION = 10;
|
private static final String USING = "using";
|
private static final String UPGRADE = "shengji";
|
private static final String UNCHANGED = "wubianhua";
|
private static final String CREATE = "xinjian";
|
|
private final DmsCurrentIdentity identity;
|
private final jnpf.dmsService.DmsBusinessLifecycleGuard businessOccupancy;
|
private final DmsWenjianBanbenMapper versionMapper;
|
private final DmsWenjianBianhaoMapper numberMapper;
|
private final DmsWenjianXinzengShenheMapper newAuditMapper;
|
private final DmsWenjianXinzengShenheJiluMingxiMapper newAuditRecordMapper;
|
private final DmsWenjianXiudingShenqingMapper revisionRequestMapper;
|
private final DmsWenjianXiudingShenqingZixiangMapper revisionDetailMapper;
|
private final DmsWenjianXiudingShenheMapper revisionAuditMapper;
|
private final DmsWenjianXiudingShenheJiluMingxiMapper revisionAuditRecordMapper;
|
private final DmsWenjianGuanlianMingxiMapper relatedDetailMapper;
|
private final DmsWenjianGuanxiMapper relationMapper;
|
private final DmsWenjianYewuBanbenService businessVersionService;
|
private final DmsWenjianFenfaService distributionService;
|
private final jnpf.dmsService.DmsApprovedFileProjection centerProjection;
|
private final jnpf.dmsMapper.DmsApprovedBatchMapper acceptanceMapper;
|
private final jnpf.dmsService.DmsApprovedAuditSource approvedSource;
|
private final jnpf.dmsService.DmsQianpiyeRenderSnapshotService qianpiyeSnapshots;
|
private final jnpf.dmsService.DmsXiudingKanwuService revisionErrata;
|
private final jnpf.dmsService.DmsExternalApprovedSettlementService externalSettlement;
|
|
@Override
|
@Transactional(readOnly = true)
|
public DmsWenjianBanbenQueryVO getByWenjianIdAndBanbenhao(
|
String wenjianId, String banbenhao) throws DataException {
|
UserInfo user = identity.requireUser();
|
String tenantId = identity.tenantId(user);
|
String resolvedWenjianId = requireText(wenjianId, "文件ID不能为空");
|
String resolvedBanbenhao = requireText(banbenhao, "版本号不能为空");
|
DmsWenjianBanbenEntity version = versionMapper.selectByFileAndVersionLabel(
|
tenantId, resolvedWenjianId, resolvedBanbenhao);
|
if (version == null) {
|
throw new DataException("未找到对应的业务文件版本");
|
}
|
|
DmsWenjianBanbenQueryVO result = new DmsWenjianBanbenQueryVO();
|
result.setId(version.getId());
|
result.setWenjianZhongxinBanbenId(version.getWenjianZhongxinBanbenId());
|
result.setWenjianZhongxinWenjianId(version.getWenjianZhongxinWenjianId());
|
return result;
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void applyApproved(jnpf.dmsEntity.storage.approval.DmsApprovedBatch batch) {
|
jnpf.dmsEntity.storage.approval.DmsApprovedBatch receipt = acceptanceMapper.lock(batch.getTenantId(), batch.getId());
|
if (receipt == null) throw new DataException("文件接收回执不存在");
|
if ("APPLIED".equals(receipt.getStatus())) return;
|
if (!"EFFECTIVE".equals(receipt.getStatus())) throw new DataException("批准文件尚未生效");
|
jnpf.dmsService.DmsApprovedAuditSource.Source nativeSource = approvedSource.load(receipt.getTenantId(), receipt.getFlowId(), receipt.getTaskId(),
|
receipt.getAuditType(), receipt.getActorId(), receipt.getApprovedAt());
|
jnpf.dmsEntity.storage.approval.DmsApprovedBatch source = nativeSource.batch();
|
var businessReceipts = "wailai_wenjian_xinzeng_shenhe".equals(receipt.getAuditType())
|
? businessOccupancy.requireExternalCreation(receipt.getTenantId(), receipt.getAuditId(),
|
receipt.getTaskId(), source.getItems().get(0).getDocumentNo())
|
: "xiuding_shenhe".equals(receipt.getAuditType())
|
? businessOccupancy.requireRevision(receipt.getTenantId(),receipt.getAuditId())
|
: businessOccupancy.requireCreation(receipt.getTenantId(),receipt.getAuditId());
|
if(businessOccupancy.isEnabled())
|
jnpf.dmsService.DmsBusinessLifecycleGuard.verifySourceCoverage(businessReceipts,source.getItems());
|
qianpiyeSnapshots.attach(source, receipt.getApprovalRenderSnapshot(),
|
nativeSource.preparedBy(), nativeSource.preparedOn());
|
if (!Objects.equals(source.getSourceDigest(), receipt.getSourceDigest()))
|
throw new DataException("批准内容发生变化,停止业务回写");
|
UserInfo actor = new UserInfo();
|
actor.setUserId(receipt.getActorId()); actor.setTenantId(receipt.getTenantId());
|
if ("wailai_wenjian_xinzeng_shenhe".equals(receipt.getAuditType())) {
|
externalSettlement.apply(receipt);
|
} else if ("xinzeng_shenhe".equals(receipt.getAuditType())) {
|
settleNew(actor, receipt.getTenantId(), receipt.getFlowId(), receipt.getTaskId(), PASSED, DmsFlowEventType.END);
|
} else {
|
settleRevision(actor, receipt.getTenantId(), receipt.getFlowId(), receipt.getTaskId(), PASSED, DmsFlowEventType.END);
|
revisionErrata.complete(receipt.getTenantId(), receipt.getAuditId(), nativeSource.errata());
|
}
|
requireSingleUpdate(acceptanceMapper.applied(receipt.getTenantId(), receipt.getId()), "标记业务回写完成失败");
|
businessOccupancy.completeExecution(businessReceipts);
|
}
|
|
/**
|
* 按当前租户和业务文件版本ID读取文件中心版本ID。
|
*/
|
@Override
|
@Transactional(readOnly = true)
|
public DmsWenjianZhongxinBanbenVO getWenjianZhongxinBanben(String fileVersionId)
|
throws DataException {
|
UserInfo user = identity.requireUser();
|
String tenantId = identity.tenantId(user);
|
String resolvedVersionId = requireText(fileVersionId, "文件版本ID不能为空");
|
DmsWenjianBanbenEntity version = versionMapper.selectById(tenantId, resolvedVersionId);
|
|
DmsWenjianZhongxinBanbenVO result = new DmsWenjianZhongxinBanbenVO();
|
if (version != null) {
|
result.setWenjianZhongxinBanbenId(trimToNull(version.getWenjianZhongxinBanbenId()));
|
}
|
return result;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void syncNewAuditFlow(String flowId, String taskId, Integer flowState,
|
DmsFlowEventType eventType) throws DataException {
|
if (Integer.valueOf(PASSED).equals(flowState)) throw new DataException("批准流程必须通过统一接收和生效入口结算");
|
UserInfo user = identity.requireUser();
|
settleNew(user, identity.tenantId(user), flowId, taskId, flowState, eventType);
|
}
|
|
private void settleNew(UserInfo user, String tenantId, String flowId, String taskId,
|
Integer flowState, DmsFlowEventType eventType) {
|
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)) {
|
distributionService.ensureNewPrintTasks(
|
tenantId, audit.getId(), audit.getWenjianId(), user.getUserId());
|
return;
|
}
|
|
String numberId = requireText(audit.getWenjianBianhaoId(), "新增审核单未关联编号申请明细");
|
DmsWenjianBianhaoEntity number = numberMapper.selectActiveByIdForUpdate(tenantId, numberId);
|
validateNewNumber(number);
|
if (flowState != PASSED) {
|
return;
|
}
|
validateTraining(audit.getShifouPeixun(), audit.getPeixunWanchengRiqi());
|
|
DmsWenjianBanbenEntity mainVersion = businessVersionService.createInitialVersion(
|
initialMainModel(tenantId, user.getUserId(), audit, number));
|
settleNewAuditRecords(tenantId, user.getUserId(), audit, mainVersion.getWenjianId());
|
settleRelatedFiles(tenantId, user.getUserId(), audit.getId(), mainVersion.getWenjianId(),
|
relatedDetailMapper.selectNewAuditRelations(tenantId, audit.getId()), false);
|
writeNewAuditResult(audit, mainVersion);
|
distributionService.ensureNewPrintTasks(
|
tenantId, audit.getId(), mainVersion.getWenjianId(), user.getUserId());
|
log.info("文件新增审核生成统一正式版本,auditId={}, wenjianId={}, versionId={}, version={}",
|
audit.getId(), mainVersion.getWenjianId(), mainVersion.getId(),
|
mainVersion.getBanbenhao());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void syncRevisionAuditFlow(String flowId, String taskId, Integer flowState,
|
DmsFlowEventType eventType) throws DataException {
|
if (Integer.valueOf(PASSED).equals(flowState)) throw new DataException("批准流程必须通过统一接收和生效入口结算");
|
UserInfo user = identity.requireUser();
|
settleRevision(user, identity.tenantId(user), flowId, taskId, flowState, eventType);
|
}
|
|
private void settleRevision(UserInfo user, String tenantId, String flowId, String taskId,
|
Integer flowState, DmsFlowEventType eventType) {
|
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 (flowState != RUNNING && flowState != PASSED) {
|
releaseRevisionDetail(tenantId, audit);
|
return;
|
}
|
|
DmsWenjianXiudingShenqingZixiangEntity detail = resolveRevisionDetail(
|
tenantId, audit);
|
String requestId = requireText(detail.getForeignId(), "修订申请子项未关联申请主单");
|
DmsWenjianXiudingShenqingEntity request =
|
revisionRequestMapper.selectByIdForUpdate(tenantId, requestId);
|
validateRevisionRequest(request);
|
if (hasCompleteRevisionResult(audit)) {
|
validateEffectiveDetail(detail, audit.getId());
|
distributionService.ensureRevisionPrintTasks(
|
tenantId, audit.getId(), audit.getWenjianId(), user.getUserId());
|
return;
|
}
|
|
claimRevisionDetail(tenantId, detail, audit.getId());
|
if (flowState == RUNNING) {
|
return;
|
}
|
|
validateChangeType(audit.getBiangengFangshi());
|
validateTraining(audit.getShifouPeixun(), audit.getPeixunWanchengRiqi());
|
DmsWenjianBanbenEntity mainVersion = settleRevisionMain(
|
tenantId, user.getUserId(), audit, detail);
|
settleRevisionAuditRecords(
|
tenantId, user.getUserId(), audit, mainVersion.getWenjianId());
|
settleRelatedFiles(tenantId, user.getUserId(), audit.getId(), mainVersion.getWenjianId(),
|
relatedDetailMapper.selectRevisionAuditRelations(tenantId, audit.getId()), true);
|
|
writeRevisionAuditResult(audit, detail, mainVersion);
|
requireSingleUpdate(revisionDetailMapper.markEffective(
|
tenantId, detail.getId(), audit.getId()), "修订申请子项生效状态更新失败");
|
// Independent occupancy is released by applyApproved only after all projections succeed.
|
distributionService.ensureRevisionPrintTasks(
|
tenantId, audit.getId(), mainVersion.getWenjianId(), user.getUserId());
|
log.info("文件修订审核结算统一正式版本,auditId={}, wenjianId={}, versionId={}, version={}",
|
audit.getId(), mainVersion.getWenjianId(), mainVersion.getId(),
|
mainVersion.getBanbenhao());
|
}
|
|
private DmsWenjianBanbenJiesuanModel initialMainModel(
|
String tenantId, String userId, DmsWenjianXinzengShenheEntity audit,
|
DmsWenjianBianhaoEntity number) throws DataException {
|
DmsWenjianBanbenJiesuanModel model = baseModel(
|
tenantId, userId, audit.getId(), null,
|
"xinzeng_shenhe:" + audit.getId() + ":zhuwenjian");
|
model.setWenjianLeixing(DmsWenjianYewuBanbenService.MAIN_FILE);
|
model.setWenjianId(trimToNull(audit.getWenjianId()));
|
model.setWenjianBianhaoId(number.getId());
|
model.setWenjianBianhao(requireText(number.getWenjianBianhao(), "编号明细缺少已发放编号"));
|
model.setWenjianMingcheng(firstText(
|
audit.getWenjianMingcheng(), number.getDangqianWenjianMingcheng(),
|
"新增审核单缺少文件名称"));
|
model.setGuishuBumenId(audit.getGuishuBumenId());
|
model.setWenjianMuluId(audit.getWenjianMuluId());
|
model.setWenjianNeirong(requireText(audit.getWenjian(), "新增审核单缺少主文件"));
|
return model;
|
}
|
|
private void settleNewAuditRecords(String tenantId, String userId,
|
DmsWenjianXinzengShenheEntity audit,
|
String mainFileId) throws DataException {
|
List<DmsWenjianXinzengShenheJiluMingxiEntity> records =
|
newAuditRecordMapper.selectByAuditForUpdate(tenantId, audit.getId());
|
if (records == null) {
|
return;
|
}
|
for (DmsWenjianXinzengShenheJiluMingxiEntity record : records) {
|
if (!blank(record.getBiangengFangshi()) && !CREATE.equals(record.getBiangengFangshi())) {
|
throw new DataException("新增审核记录的变更方式只能为新建");
|
}
|
if (!blank(record.getBanbenhao()) && !formatVersion(0).equals(record.getBanbenhao())) {
|
throw new DataException("新增审核记录的版本必须为D(00)");
|
}
|
DmsWenjianBanbenJiesuanModel model = baseModel(
|
tenantId, userId, audit.getId(), record.getId(),
|
"xinzeng_shenhe:" + audit.getId() + ":jilu:" + record.getId());
|
model.setWenjianId(trimToNull(record.getJiluWenjianId()));
|
model.setWenjianLeixing(DmsWenjianYewuBanbenService.RECORD_FILE);
|
model.setWenjianBianhao(requireText(record.getFujianBianhao(), "记录编号不能为空"));
|
model.setWenjianMingcheng(requireText(record.getFujianMingcheng(), "记录名称不能为空"));
|
model.setJiluLeixing(record.getJiluLeixing());
|
model.setDengji(record.getDengji());
|
requireSameDirectory(audit.getWenjianMuluId(), record.getWenjianMuluId());
|
model.setWenjianMuluId(record.getWenjianMuluId());
|
model.setJiluDengjiGuanliId(record.getJiluDengjiGuanliId());
|
model.setJiluDengjiGuanliBanben(record.getJiluDengjiGuanliBanben());
|
model.setGuishuBumenId(record.getGuishuBumenId());
|
model.setWenjianNeirong(requireText(record.getJiluWenjian(), "记录文件不能为空"));
|
DmsWenjianBanbenEntity version = businessVersionService.createInitialVersion(model);
|
businessVersionService.ensureRelation(
|
tenantId, mainFileId, version.getWenjianId(),
|
DmsWenjianYewuBanbenService.RELATION_RECORD, audit.getId(), userId);
|
if (blank(record.getShengxiaoWenjianBanbenId())) {
|
record.setBiangengFangshi(CREATE);
|
record.setBanbenhao(version.getBanbenhao());
|
record.setJiluWenjianId(version.getWenjianId());
|
record.setYuanWenjianBanbenId(null);
|
record.setShengxiaoWenjianBanbenId(version.getId());
|
requireSingleUpdate(newAuditRecordMapper.updateSettlement(record),
|
"回写新增审核记录文件版本失败");
|
}
|
}
|
}
|
|
private DmsWenjianBanbenEntity settleRevisionMain(
|
String tenantId, String userId, DmsWenjianXiudingShenheEntity audit,
|
DmsWenjianXiudingShenqingZixiangEntity detail) throws DataException {
|
String fileId = requireText(detail.getWenjianId(), "修订申请子项未关联文件");
|
String sourceVersionId = requireText(
|
detail.getYuanWenjianBanbenId(), "修订申请子项缺少来源文件版本ID");
|
if (UPGRADE.equals(audit.getBiangengFangshi())) {
|
DmsWenjianBanbenJiesuanModel model = baseModel(
|
tenantId, userId, audit.getId(), null,
|
"xiuding_shenhe:" + audit.getId() + ":zhuwenjian");
|
model.setWenjianId(fileId);
|
model.setWenjianLeixing(DmsWenjianYewuBanbenService.MAIN_FILE);
|
model.setYuanWenjianBanbenId(sourceVersionId);
|
model.setWenjianMingcheng(audit.getWenjianMingcheng());
|
model.setGuishuBumenId(audit.getGuishuBumenId());
|
model.setWenjianMuluId(audit.getWenjianMuluId());
|
model.setWenjianNeirong(requireText(audit.getWenjian(), "修订审核单缺少主文件"));
|
return businessVersionService.createRevisionVersion(model);
|
}
|
DmsWenjianBanbenEntity current = businessVersionService.reuseCurrentVersion(
|
tenantId, fileId, sourceVersionId);
|
if (!blank(audit.getWenjian()) && !sameContent(
|
audit.getWenjian().trim(), current.getWenjianNeirong())) {
|
throw new DataException("主文件选择无变化时不能替换文件内容");
|
}
|
return current;
|
}
|
|
private void settleRevisionAuditRecords(String tenantId, String userId,
|
DmsWenjianXiudingShenheEntity audit,
|
String mainFileId) throws DataException {
|
List<DmsWenjianXiudingShenheJiluMingxiEntity> records =
|
revisionAuditRecordMapper.selectByAuditForUpdate(tenantId, audit.getId());
|
Set<String> retainedFileIds = new HashSet<>();
|
if (records != null) {
|
for (DmsWenjianXiudingShenheJiluMingxiEntity record : records) {
|
settleRevisionRecord(tenantId, userId, audit, mainFileId, record,
|
retainedFileIds);
|
}
|
}
|
DmsApprovedBatch batch = acceptanceMapper.find(tenantId, audit.getFlowTaskId(), "xiuding_shenhe");
|
if (batch == null || !"EFFECTIVE".equals(batch.getStatus()))
|
throw new DataException("修订记录尚未完成中心生效");
|
Set<String> retired = new HashSet<>();
|
for (DmsApprovedItem item : acceptanceMapper.items(tenantId, batch.getId())) {
|
if (!"RETIRE".equals(item.getChangeType())) continue;
|
if (retainedFileIds.contains(item.getFileId()) || !retired.add(item.getFileId()))
|
throw new DataException("移除记录与批准明细不一致");
|
businessVersionService.retireRecord(tenantId, mainFileId, item.getFileId(),
|
item.getBusinessVersionId(), userId);
|
}
|
requireAllExistingRelationsRetained(tenantId, mainFileId,
|
DmsWenjianYewuBanbenService.RELATION_RECORD, retainedFileIds,
|
"记录归属已变化,存在未经批准移除的记录");
|
}
|
|
private void settleRevisionRecord(String tenantId, String userId,
|
DmsWenjianXiudingShenheEntity audit,
|
String mainFileId,
|
DmsWenjianXiudingShenheJiluMingxiEntity record,
|
Set<String> retainedFileIds) throws DataException {
|
String changeType = requireText(record.getBiangengFangshi(), "记录变更方式不能为空");
|
DmsWenjianBanbenEntity version;
|
if (CREATE.equals(changeType)) {
|
DmsWenjianBanbenJiesuanModel model = baseModel(
|
tenantId, userId, audit.getId(), record.getId(),
|
"xiuding_shenhe:" + audit.getId() + ":jilu:" + record.getId());
|
model.setWenjianId(trimToNull(record.getJiluWenjianId()));
|
model.setWenjianLeixing(DmsWenjianYewuBanbenService.RECORD_FILE);
|
model.setWenjianBianhao(requireText(record.getFujianBianhao(), "记录编号不能为空"));
|
model.setWenjianMingcheng(requireText(record.getFujianMingcheng(), "记录名称不能为空"));
|
model.setJiluLeixing(record.getJiluLeixing());
|
model.setDengji(record.getDengji());
|
requireSameDirectory(audit.getWenjianMuluId(), record.getWenjianMuluId());
|
model.setWenjianMuluId(record.getWenjianMuluId());
|
model.setJiluDengjiGuanliId(record.getJiluDengjiGuanliId());
|
model.setJiluDengjiGuanliBanben(record.getJiluDengjiGuanliBanben());
|
model.setGuishuBumenId(record.getGuishuBumenId());
|
model.setWenjianNeirong(requireText(record.getJiluWenjian(), "记录文件不能为空"));
|
version = businessVersionService.createInitialVersion(model);
|
} else {
|
String recordFileId = requireText(record.getJiluWenjianId(), "现行记录缺少记录文件ID");
|
String sourceVersionId = requireText(
|
record.getYuanWenjianBanbenId(), "现行记录缺少来源文件版本ID");
|
if (!retainedFileIds.add(recordFileId)) {
|
throw new DataException("修订审核单包含重复的记录文件");
|
}
|
if (UPGRADE.equals(changeType)) {
|
DmsWenjianBanbenJiesuanModel model = baseModel(
|
tenantId, userId, audit.getId(), record.getId(),
|
"xiuding_shenhe:" + audit.getId() + ":jilu:" + record.getId());
|
model.setWenjianId(recordFileId);
|
model.setWenjianLeixing(DmsWenjianYewuBanbenService.RECORD_FILE);
|
model.setYuanWenjianBanbenId(sourceVersionId);
|
model.setWenjianMingcheng(record.getFujianMingcheng());
|
model.setJiluLeixing(record.getJiluLeixing());
|
model.setDengji(record.getDengji());
|
requireSameDirectory(audit.getWenjianMuluId(), record.getWenjianMuluId());
|
model.setWenjianMuluId(record.getWenjianMuluId());
|
model.setJiluDengjiGuanliId(record.getJiluDengjiGuanliId());
|
model.setJiluDengjiGuanliBanben(record.getJiluDengjiGuanliBanben());
|
model.setGuishuBumenId(record.getGuishuBumenId());
|
model.setWenjianNeirong(requireText(record.getJiluWenjian(), "记录文件不能为空"));
|
version = businessVersionService.createRevisionVersion(model);
|
} else if (UNCHANGED.equals(changeType)) {
|
version = businessVersionService.reuseCurrentVersion(
|
tenantId, recordFileId, sourceVersionId);
|
if (!blank(record.getJiluWenjian()) && !sameContent(
|
record.getJiluWenjian().trim(), version.getWenjianNeirong())) {
|
throw new DataException("记录选择无变化时不能替换文件内容");
|
}
|
requireSameDirectory(audit.getWenjianMuluId(), record.getWenjianMuluId());
|
// applyApproved reloaded this native record and verified its approval digest.
|
// REUSE has no new center registration; old receipts may lack a control snapshot.
|
DmsWenjianBanbenJiesuanModel model = new DmsWenjianBanbenJiesuanModel();
|
model.setTenantId(tenantId);
|
model.setUserId(userId);
|
model.setLaiyuanDanjuLeixing("xiuding_shenhe");
|
model.setLaiyuanDanjuId(audit.getId());
|
model.setLaiyuanZixiangId(record.getId());
|
model.setCenterVersionId(version.getWenjianZhongxinBanbenId());
|
model.setShifouShoukong(record.getShifouShoukong());
|
model.setWenjianId(recordFileId);
|
model.setYuanWenjianBanbenId(sourceVersionId);
|
model.setWenjianLeixing(DmsWenjianYewuBanbenService.RECORD_FILE);
|
model.setWenjianMingcheng(record.getFujianMingcheng());
|
model.setGuishuBumenId(record.getGuishuBumenId());
|
model.setWenjianMuluId(record.getWenjianMuluId());
|
version = businessVersionService.updateReusedRecordMetadata(model);
|
} else {
|
throw new DataException("记录变更方式无效");
|
}
|
}
|
|
retainedFileIds.add(version.getWenjianId());
|
businessVersionService.ensureRelation(
|
tenantId, mainFileId, version.getWenjianId(),
|
DmsWenjianYewuBanbenService.RELATION_RECORD, audit.getId(), userId);
|
if (blank(record.getShengxiaoWenjianBanbenId())) {
|
record.setBanbenhao(version.getBanbenhao());
|
record.setJiluWenjianId(version.getWenjianId());
|
record.setShengxiaoWenjianBanbenId(version.getId());
|
requireSingleUpdate(revisionAuditRecordMapper.updateSettlement(record),
|
"回写修订审核记录文件版本失败");
|
}
|
}
|
|
private void requireSameDirectory(String main, String record) throws DataException {
|
if (blank(main) || !Objects.equals(main, record)) {
|
throw new DataException("记录子表目录必须与主表一致");
|
}
|
}
|
|
private void settleRelatedFiles(String tenantId, String userId, String auditId,
|
String mainFileId,
|
List<DmsWenjianGuanlianMingxiEntity> rows,
|
boolean requireExisting) throws DataException {
|
Set<String> retainedFileIds = new HashSet<>();
|
if (rows != null) {
|
for (DmsWenjianGuanlianMingxiEntity row : rows) {
|
String relatedFileId = requireText(
|
row.getGuanlianWenjianId(), "关联文件明细缺少文件ID");
|
if (!retainedFileIds.add(relatedFileId)) {
|
throw new DataException("审核单包含重复的关联文件");
|
}
|
businessVersionService.ensureRelation(
|
tenantId, mainFileId, relatedFileId, "guanlian_wenjian", auditId, userId);
|
}
|
}
|
if (requireExisting) {
|
requireAllExistingRelationsRetained(
|
tenantId, mainFileId, "guanlian_wenjian", retainedFileIds,
|
"现行关联文件不能从修订审核单中删除");
|
}
|
}
|
|
private void requireAllExistingRelationsRetained(String tenantId, String mainFileId,
|
String relationType,
|
Set<String> retainedFileIds,
|
String message) throws DataException {
|
List<DmsWenjianGuanxiEntity> existing = relationMapper.selectEffectiveByMainAndType(
|
tenantId, mainFileId, relationType);
|
if (existing == null) {
|
return;
|
}
|
for (DmsWenjianGuanxiEntity relation : existing) {
|
if (!retainedFileIds.contains(relation.getGuanlianWenjianId())) {
|
throw new DataException(message);
|
}
|
}
|
}
|
|
private DmsWenjianBanbenJiesuanModel baseModel(
|
String tenantId, String userId, String auditId, String rowId,
|
String sourceBusinessKey) {
|
DmsWenjianBanbenJiesuanModel model = new DmsWenjianBanbenJiesuanModel();
|
model.setTenantId(tenantId);
|
model.setLaiyuanDanjuLeixing(sourceBusinessKey.startsWith("xinzeng_shenhe:")
|
? "xinzeng_shenhe" : "xiuding_shenhe");
|
model.setLaiyuanDanjuId(auditId);
|
model.setLaiyuanZixiangId(rowId);
|
model.setLaiyuanYewuJian(sourceBusinessKey);
|
model.setUserId(userId);
|
centerProjection.enrich(model);
|
return model;
|
}
|
|
private void writeNewAuditResult(DmsWenjianXinzengShenheEntity audit,
|
DmsWenjianBanbenEntity version) throws DataException {
|
audit.setWenjianId(version.getWenjianId());
|
audit.setShengxiaoWenjianBanbenId(version.getId());
|
audit.setBanbenShengxiaoShijian(version.getShengxiaoShijian());
|
requireSingleUpdate(newAuditMapper.updateEffectiveVersion(audit),
|
"回写新增审核生效文件版本失败");
|
}
|
|
private void writeRevisionAuditResult(DmsWenjianXiudingShenheEntity audit,
|
DmsWenjianXiudingShenqingZixiangEntity detail,
|
DmsWenjianBanbenEntity version) throws DataException {
|
audit.setWenjianId(version.getWenjianId());
|
audit.setYuanWenjianBanbenId(detail.getYuanWenjianBanbenId());
|
audit.setShengxiaoWenjianBanbenId(version.getId());
|
jnpf.dmsEntity.storage.approval.DmsApprovedBatch receipt = acceptanceMapper.find(audit.getTenantId(), audit.getFlowTaskId(), "xiuding_shenhe");
|
audit.setBanbenShengxiaoShijian(receipt.getActivatedAt());
|
requireSingleUpdate(revisionAuditMapper.updateEffectiveVersion(audit),
|
"回写修订审核生效文件版本失败");
|
}
|
|
private void validateNewNumber(DmsWenjianBianhaoEntity number) throws DataException {
|
if (number == null) {
|
throw new DataException("未找到新增审核单关联的编号申请明细");
|
}
|
if (!USING.equals(number.getBizStatus()) || blank(number.getWenjianBianhao())) {
|
throw new DataException("关联编号尚未完成发放");
|
}
|
if (blank(number.getDangqianWenjianMingcheng())) {
|
throw new DataException("编号申请明细缺少文件名称");
|
}
|
}
|
|
private void validateRevisionRequest(DmsWenjianXiudingShenqingEntity request)
|
throws DataException {
|
if (request == null) {
|
throw new DataException("未找到修订审核单关联的修订申请");
|
}
|
if (!Objects.equals(request.getFlowState(), PASSED)) {
|
throw new DataException("关联的文件修订申请尚未审批通过");
|
}
|
}
|
|
private DmsWenjianXiudingShenqingZixiangEntity resolveRevisionDetail(
|
String tenantId, DmsWenjianXiudingShenheEntity audit) throws DataException {
|
String detailId = requireText(audit.getXiudingShenqingZixiangId(),
|
"修订审核单未关联修订申请子项");
|
DmsWenjianXiudingShenqingZixiangEntity detail =
|
revisionDetailMapper.selectByIdForUpdate(tenantId, detailId);
|
if (detail == null) {
|
throw new DataException("修订审核单关联的修订申请子项无效");
|
}
|
requireText(detail.getWenjianId(), "修订申请子项未关联文件");
|
requireText(detail.getYuanWenjianBanbenId(), "修订申请子项缺少来源文件版本ID");
|
return detail;
|
}
|
|
private void claimRevisionDetail(String tenantId,
|
DmsWenjianXiudingShenqingZixiangEntity detail,
|
String auditId) throws DataException {
|
if ("occupied".equals(detail.getBizStatus())
|
&& auditId.equals(detail.getZhanYongDanjuId())) {
|
return;
|
}
|
requireSingleUpdate(revisionDetailMapper.claim(tenantId, detail.getId(), auditId),
|
"该修订申请子项已被其他审核单占用");
|
}
|
|
private void releaseRevisionDetail(String tenantId, DmsWenjianXiudingShenheEntity audit) {
|
if (!blank(audit.getXiudingShenqingZixiangId())) {
|
revisionDetailMapper.release(
|
tenantId, audit.getXiudingShenqingZixiangId(), audit.getId());
|
}
|
}
|
|
private void validateEffectiveDetail(DmsWenjianXiudingShenqingZixiangEntity detail,
|
String auditId) throws DataException {
|
if (!"effective".equals(detail.getBizStatus())
|
|| !auditId.equals(detail.getZhanYongDanjuId())) {
|
throw new DataException("修订审核单与修订申请子项生效状态不一致");
|
}
|
}
|
|
private void validateChangeType(String changeType) throws DataException {
|
if (!UPGRADE.equals(changeType) && !UNCHANGED.equals(changeType)) {
|
throw new DataException("修订审核单的主文件变更方式无效");
|
}
|
}
|
|
private void validateTraining(String trainingType, Date completedAt) throws DataException {
|
String type = requireText(trainingType, "文件审核单未选择是否培训");
|
if (!"peixun".equals(type) && !"buPeixun".equals(type)) {
|
throw new DataException("文件审核单的培训选项无效");
|
}
|
if ("peixun".equals(type) && completedAt == null) {
|
throw new DataException("文件培训尚未完成,不能生效");
|
}
|
}
|
|
private boolean hasCompleteNewResult(DmsWenjianXinzengShenheEntity audit)
|
throws DataException {
|
boolean any = !blank(audit.getWenjianId())
|
|| !blank(audit.getShengxiaoWenjianBanbenId())
|
|| audit.getBanbenShengxiaoShijian() != null;
|
if (!any) {
|
return false;
|
}
|
if (blank(audit.getWenjianId()) || blank(audit.getShengxiaoWenjianBanbenId())
|
|| audit.getBanbenShengxiaoShijian() == null) {
|
throw new DataException("新增审核单的生效文件版本结果不完整");
|
}
|
return true;
|
}
|
|
private boolean hasCompleteRevisionResult(DmsWenjianXiudingShenheEntity audit)
|
throws DataException {
|
boolean any = !blank(audit.getShengxiaoWenjianBanbenId())
|
|| audit.getBanbenShengxiaoShijian() != null;
|
if (!any) {
|
return false;
|
}
|
if (blank(audit.getWenjianId()) || blank(audit.getYuanWenjianBanbenId())
|
|| blank(audit.getShengxiaoWenjianBanbenId())
|
|| audit.getBanbenShengxiaoShijian() == null) {
|
throw new DataException("修订审核单的生效文件版本结果不完整");
|
}
|
return true;
|
}
|
|
@org.springframework.beans.factory.annotation.Autowired
|
private jnpf.file.FileContentApi fileContentApi;
|
|
private boolean sameContent(String left, String right) {
|
return jnpf.file.FileContentEquality.same(left, right, fileContentApi);
|
}
|
|
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 firstText(String first, String second, String message) throws DataException {
|
return !blank(first) ? first.trim() : requireText(second, message);
|
}
|
|
private String requireText(String value, String message) throws DataException {
|
if (blank(value)) {
|
throw new DataException(message);
|
}
|
return value.trim();
|
}
|
|
private String trimToNull(String value) {
|
return blank(value) ? null : value.trim();
|
}
|
|
private boolean blank(String value) {
|
return value == null || value.trim().isEmpty();
|
}
|
|
private void requireSingleUpdate(int affected, String message) throws DataException {
|
if (affected != 1) {
|
throw new DataException(message);
|
}
|
}
|
|
static String formatVersion(int sequence) {
|
return DmsWenjianYewuBanbenService.formatVersion(sequence);
|
}
|
}
|