package jnpf.dmsService.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import jnpf.audit.sdk.annotation.AuditLog;
|
import jnpf.base.ActionResult;
|
import jnpf.base.ActionResultCode;
|
import jnpf.base.UserInfo;
|
import jnpf.dmsEntity.DmsWenjianFushenJihuaFenpeiZixiangEntity;
|
import jnpf.dmsEntity.DmsWenjianFushenZhixingEntity;
|
import jnpf.dmsEntity.DmsWenjianFushenZhixingZixiangEntity;
|
import jnpf.dmsEntity.DmsWenjianZiyuanEntity;
|
import jnpf.dmsEntity.storage.form.DmsFileExtendValidityForm;
|
import jnpf.dmsEntity.storage.form.DmsFileExtendValidityForm.FileRequest;
|
import jnpf.dmsEntity.form.DmsWenjianFushenZhixingBatchReturnForm;
|
import jnpf.dmsMapper.DmsWenjianFushenJihuaFenpeiZixiangMapper;
|
import jnpf.dmsMapper.DmsWenjianFushenZhixingMapper;
|
import jnpf.dmsMapper.DmsWenjianFushenZhixingZixiangMapper;
|
import jnpf.dmsMapper.DmsWenjianZiyuanMapper;
|
import jnpf.dmsPermission.DmsCurrentIdentity;
|
import jnpf.dmsService.DmsFileValidityService;
|
import jnpf.dmsService.DmsWenjianFushenZhixingService;
|
import jnpf.exception.DataException;
|
import jnpf.flowable.TaskApi;
|
import jnpf.flowable.WorkFlowApi;
|
import jnpf.flowable.entity.TemplateJsonEntity;
|
import jnpf.flowable.enums.TemplateJsonStatueEnum;
|
import jnpf.flowable.model.task.FlowModel;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.text.SimpleDateFormat;
|
import java.time.ZoneId;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.Date;
|
import java.util.HashMap;
|
import java.util.LinkedHashSet;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.UUID;
|
|
@Service
|
@RequiredArgsConstructor
|
public class DmsWenjianFushenZhixingServiceImpl implements DmsWenjianFushenZhixingService {
|
|
private static final String KEYANYONG = "keyanyong";
|
private static final String XUXIUDING = "xuxiuding";
|
private static final String XUCHEXIAO = "xuchexiao";
|
private static final String REVISION_TEMPLATE_ID = "861598967111148613";
|
private static final String REVOCATION_TEMPLATE_ID = "859064410424006213";
|
private static final ZoneId SHANGHAI_ZONE = ZoneId.of("Asia/Shanghai");
|
private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
|
|
private final DmsWenjianFushenJihuaFenpeiZixiangMapper zixiangMapper;
|
private final DmsWenjianFushenZhixingMapper zhixingMapper;
|
private final DmsWenjianFushenZhixingZixiangMapper zhixingZixiangMapper;
|
private final DmsWenjianZiyuanMapper ziyuanMapper;
|
private final DmsFileValidityService fileValidityService;
|
private final DmsCurrentIdentity identity;
|
private final TaskApi taskApi;
|
private final WorkFlowApi workFlowApi;
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
@AuditLog(
|
action = "FILE_REVIEW_BATCH_RETURN",
|
label = "文件复审执行批量退回",
|
bizModule = "文件复审执行",
|
bizType = "DMS_FILE_REVIEW",
|
bizCodeExpr = "",
|
bizCodeRequired = false,
|
targetTable = "wenjian_fushen_jihua_fenpei_zixiang",
|
targetIdExpr = "#p0[0].fenpeiZixiangId",
|
targetIdsExpr = "#p0.![fenpeiZixiangId]",
|
diff = true,
|
entityClass = DmsWenjianFushenJihuaFenpeiZixiangEntity.class
|
)
|
public void batchReturn(List<DmsWenjianFushenZhixingBatchReturnForm> forms) throws DataException {
|
Set<String> zixiangIds = resolveZixiangIds(forms);
|
|
LambdaUpdateWrapper<DmsWenjianFushenJihuaFenpeiZixiangEntity> update = new LambdaUpdateWrapper<>();
|
update.in(DmsWenjianFushenJihuaFenpeiZixiangEntity::getId, zixiangIds)
|
.isNull(DmsWenjianFushenJihuaFenpeiZixiangEntity::getDeleteMark)
|
.set(DmsWenjianFushenJihuaFenpeiZixiangEntity::getHuiguRen, null)
|
.set(DmsWenjianFushenJihuaFenpeiZixiangEntity::getFenpeiBumenId, null)
|
.set(DmsWenjianFushenJihuaFenpeiZixiangEntity::getFenpeiBumenFuzeren, null)
|
.set(DmsWenjianFushenJihuaFenpeiZixiangEntity::getFenpeiRiqi, null)
|
.set(DmsWenjianFushenJihuaFenpeiZixiangEntity::getBizStatus, "daifenpei");
|
if (zixiangMapper.update(null, update) != zixiangIds.size()) {
|
throw new DataException("存在未找到或已退回的文件复审计划分配子项,无法批量退回");
|
}
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
@AuditLog(
|
action = "FILE_REVIEW_EXECUTION_WRITE_BACK",
|
label = "文件复审执行结果回写",
|
bizModule = "文件复审执行",
|
bizType = "DMS_FILE_REVIEW",
|
bizCodeExpr = "",
|
bizCodeRequired = false,
|
targetTable = "wenjian_fushen_zhixing",
|
targetIdExpr = "#p0"
|
)
|
public void writeBack(String fId) throws DataException {
|
String zhixingId = requireValue(fId, "文件复审执行ID(f_id)");
|
DmsWenjianFushenZhixingEntity zhixing = findZhixing(zhixingId);
|
List<DmsWenjianFushenZhixingZixiangEntity> zhixingZixiangs = findZhixingZixiangs(zhixingId);
|
Set<String> fenpeiZixiangIds = new LinkedHashSet<>();
|
|
for (DmsWenjianFushenZhixingZixiangEntity zhixingZixiang : zhixingZixiangs) {
|
String fenpeiZixiangId = requireValue(zhixingZixiang.getFenpeiZixiangId(),
|
"文件复审执行子项fenpei_zixiang_id");
|
if (!fenpeiZixiangIds.add(fenpeiZixiangId)) {
|
throw new DataException("文件复审执行子项不能关联重复的fenpei_zixiang_id");
|
}
|
}
|
for (DmsWenjianFushenZhixingZixiangEntity zhixingZixiang : zhixingZixiangs) {
|
String fenpeiZixiangId = zhixingZixiang.getFenpeiZixiangId().trim();
|
writeBackZixiang(zhixing, zhixingZixiang, fenpeiZixiangId);
|
}
|
handleConclusionGroups(zhixing, zhixingZixiangs);
|
}
|
|
private void handleConclusionGroups(DmsWenjianFushenZhixingEntity zhixing,
|
List<DmsWenjianFushenZhixingZixiangEntity> zixiangs) throws DataException {
|
Map<String, List<DmsWenjianFushenZhixingZixiangEntity>> groups = new LinkedHashMap<>();
|
for (DmsWenjianFushenZhixingZixiangEntity zixiang : zixiangs) {
|
String conclusion = trimToNull(zixiang.getZuizhongJielun());
|
if (conclusion != null) {
|
groups.computeIfAbsent(conclusion, key -> new ArrayList<>()).add(zixiang);
|
}
|
}
|
for (Map.Entry<String, List<DmsWenjianFushenZhixingZixiangEntity>> entry : groups.entrySet()) {
|
if (KEYANYONG.equals(entry.getKey())) {
|
extendUsableFiles(zhixing.getId(), entry.getValue());
|
} else if (XUXIUDING.equals(entry.getKey())) {
|
createRevisionDraft(entry.getValue());
|
} else if (XUCHEXIAO.equals(entry.getKey())) {
|
createRevocationDraft(entry.getValue());
|
}
|
}
|
}
|
|
private void extendUsableFiles(String zhixingId,
|
List<DmsWenjianFushenZhixingZixiangEntity> zixiangs) throws DataException {
|
UserInfo user = identity.requireUser();
|
String tenantId = identity.tenantId(user);
|
String fushenRiqi = formatDate(new Date());
|
Set<String> wenjianIds = new LinkedHashSet<>();
|
Set<UUID> fileVersionIds = new LinkedHashSet<>();
|
List<FileRequest> files = new ArrayList<>(zixiangs.size());
|
List<ReviewExtension> extensions = new ArrayList<>(zixiangs.size());
|
|
for (DmsWenjianFushenZhixingZixiangEntity zixiang : zixiangs) {
|
String wenjianId = requireValue(zixiang.getWenjianId(), "文件复审执行子项wenjian_id");
|
if (!wenjianIds.add(wenjianId)) {
|
throw new DataException("最终结论为keyanyong的文件复审执行子项不能关联重复wenjian_id");
|
}
|
// Read the expected version without a resource lock. The validity service locks documents first.
|
DmsWenjianZiyuanEntity ziyuan = ziyuanMapper.selectByTenantAndId(tenantId, wenjianId);
|
if (ziyuan == null) {
|
throw new DataException("未找到可延期的文件资源:wenjian_id=" + wenjianId);
|
}
|
UUID fileVersionId = parseFileVersionId(ziyuan.getWenjianZhongxinBanbenId(), wenjianId);
|
if (!fileVersionIds.add(fileVersionId)) {
|
throw new DataException("最终结论为keyanyong的文件复审执行子项不能关联重复文件版本");
|
}
|
Date effectiveTo = extendThreeYearsToEndOfDay(ziyuan.getYouxiaoQiZhi(), wenjianId);
|
FileRequest file = new FileRequest();
|
file.setFileVersionId(fileVersionId);
|
file.setEffectiveTo(effectiveTo);
|
files.add(file);
|
extensions.add(new ReviewExtension(wenjianId, effectiveTo));
|
}
|
|
DmsFileExtendValidityForm form = new DmsFileExtendValidityForm();
|
form.setSourceId("");
|
form.setTaskId("");
|
form.setFiles(files);
|
fileValidityService.extendValidity(form);
|
for (ReviewExtension extension : extensions) {
|
if (ziyuanMapper.updateReviewExecutionExtension(tenantId, extension.wenjianId,
|
extension.effectiveTo, zhixingId, fushenRiqi) != 1) {
|
throw new DataException("文件复审执行延期回写失败:wenjian_id=" + extension.wenjianId);
|
}
|
}
|
}
|
|
private void createRevisionDraft(List<DmsWenjianFushenZhixingZixiangEntity> zixiangs)
|
throws DataException {
|
UserInfo user = identity.requireUser();
|
String tenantId = identity.tenantId(user);
|
List<Map<String, Object>> details = new ArrayList<>(zixiangs.size());
|
for (DmsWenjianFushenZhixingZixiangEntity zixiang : zixiangs) {
|
String wenjianId = requireValue(zixiang.getWenjianId(), "文件复审执行子项wenjian_id");
|
DmsWenjianZiyuanEntity ziyuan = requireResource(tenantId, wenjianId);
|
Map<String, Object> detail = new HashMap<>();
|
detail.put("wenjian_id", wenjianId);
|
detail.put("wenjian_bianhao", valueOrEmpty(zixiang.getWenjianBianhao(), ziyuan.getWenjianBianhao()));
|
detail.put("wenjian_mingcheng", valueOrEmpty(zixiang.getWenjianMingcheng(), ziyuan.getWenjianMingcheng()));
|
detail.put("yuan_wenjian_banben_id", ziyuan.getDangqianBanbenId());
|
detail.put("banbenhao", valueOrEmpty(zixiang.getBanbenhao(), null));
|
detail.put("biangeng_neirong", Collections.singletonList("wenjian"));
|
detail.put("biz_status", "available");
|
details.add(detail);
|
}
|
Map<String, Object> formData = draftHeader(user, "文件复审结论为需修订,待申请人补充修订内容。");
|
formData.put("tiyi_yuanyin_mudi", "wenjianFushen");
|
formData.put("xiuding_shenqing_zixiang", details);
|
saveDraft(REVISION_TEMPLATE_ID, user, formData, "文件修订申请");
|
}
|
|
private void createRevocationDraft(List<DmsWenjianFushenZhixingZixiangEntity> zixiangs)
|
throws DataException {
|
UserInfo user = identity.requireUser();
|
String tenantId = identity.tenantId(user);
|
List<Map<String, Object>> details = new ArrayList<>(zixiangs.size());
|
for (DmsWenjianFushenZhixingZixiangEntity zixiang : zixiangs) {
|
String wenjianId = requireValue(zixiang.getWenjianId(), "文件复审执行子项wenjian_id");
|
DmsWenjianZiyuanEntity ziyuan = requireResource(tenantId, wenjianId);
|
Map<String, Object> detail = new HashMap<>();
|
detail.put("wenjian_id", wenjianId);
|
detail.put("wenjian_banben_id", requireValue(ziyuan.getDangqianBanbenId(), "待撤销文件当前版本"));
|
detail.put("wenjian_bianhao", valueOrEmpty(zixiang.getWenjianBianhao(), ziyuan.getWenjianBianhao()));
|
detail.put("wenjian_mingcheng", valueOrEmpty(zixiang.getWenjianMingcheng(), ziyuan.getWenjianMingcheng()));
|
detail.put("banben_hao", requireValue(ziyuan.getDangqianBanbenhao(), "待撤销文件当前版本号"));
|
detail.put("tiyi_yuanyin_mudi", "文件复审结论为需撤销,待申请人补充撤销原因。");
|
details.add(detail);
|
}
|
Map<String, Object> formData = draftHeader(user, null);
|
formData.put("biz_status", "draft");
|
formData.put("chexiao_wenjian_mingxi", details);
|
saveDraft(REVOCATION_TEMPLATE_ID, user, formData, "文件撤销申请");
|
}
|
|
private Map<String, Object> draftHeader(UserInfo user, String summary) {
|
Map<String, Object> formData = new HashMap<>();
|
formData.put("tiyi_bumen_id", trimToNull(user.getOrganizeId()));
|
formData.put("tiyi_ren_id", user.getUserId());
|
formData.put("tiyi_riqi", new Date());
|
if (summary != null) {
|
formData.put("gaiban_neirong_gaishu", summary);
|
}
|
return formData;
|
}
|
|
private void saveDraft(String templateId, UserInfo user, Map<String, Object> formData, String flowName)
|
throws DataException {
|
FlowModel model = new FlowModel();
|
model.setFlowId(resolveActiveFlowVersion(templateId));
|
model.setStatus(0);
|
model.setIsFlow(1);
|
model.setUserInfo(user);
|
model.setFormData(formData);
|
ActionResult<?> result = taskApi.saveDraft(model);
|
if (result == null || !ActionResultCode.SUCCESS.getCode().equals(result.getCode())) {
|
throw new DataException("创建" + flowName + "暂存失败:" + (result == null ? "无返回" : result.getMsg()));
|
}
|
}
|
|
private String resolveActiveFlowVersion(String templateId) throws DataException {
|
List<TemplateJsonEntity> versions = workFlowApi.getFlowIdsByTemplate(templateId);
|
if (versions != null) {
|
for (TemplateJsonEntity version : versions) {
|
if (version != null && TemplateJsonStatueEnum.START.getCode().equals(version.getState())
|
&& trimToNull(version.getId()) != null) {
|
return version.getId().trim();
|
}
|
}
|
}
|
throw new DataException("未找到已启用的流程版本:template_id=" + templateId);
|
}
|
|
private DmsWenjianZiyuanEntity requireResource(String tenantId, String wenjianId) throws DataException {
|
DmsWenjianZiyuanEntity ziyuan = ziyuanMapper.selectByTenantAndId(tenantId, wenjianId);
|
if (ziyuan == null) {
|
throw new DataException("未找到文件资源:wenjian_id=" + wenjianId);
|
}
|
return ziyuan;
|
}
|
|
private UUID parseFileVersionId(String value, String wenjianId) throws DataException {
|
String fileVersionId = requireValue(value, "文件中心版本ID:wenjian_id=" + wenjianId);
|
try {
|
return UUID.fromString(fileVersionId);
|
} catch (IllegalArgumentException exception) {
|
throw new DataException("文件中心版本ID格式不正确:wenjian_id=" + wenjianId);
|
}
|
}
|
|
private Date extendThreeYearsToEndOfDay(Date value, String wenjianId) throws DataException {
|
if (value == null) {
|
throw new DataException("文件资源youxiao_qi_zhi不能为空:wenjian_id=" + wenjianId);
|
}
|
return Date.from(value.toInstant().atZone(SHANGHAI_ZONE).plusYears(3).toInstant());
|
}
|
|
private String formatDate(Date value) {
|
return new SimpleDateFormat(DATE_TIME_PATTERN).format(value);
|
}
|
|
private String valueOrEmpty(String preferred, String fallback) {
|
String value = trimToNull(preferred);
|
return value == null ? (fallback == null ? "" : fallback) : value;
|
}
|
|
private String trimToNull(String value) {
|
String trimmed = value == null ? "" : value.trim();
|
return trimmed.isEmpty() ? null : trimmed;
|
}
|
|
private DmsWenjianFushenZhixingEntity findZhixing(String zhixingId) throws DataException {
|
LambdaQueryWrapper<DmsWenjianFushenZhixingEntity> query = new LambdaQueryWrapper<>();
|
query.eq(DmsWenjianFushenZhixingEntity::getId, zhixingId)
|
.isNull(DmsWenjianFushenZhixingEntity::getDeleteMark);
|
DmsWenjianFushenZhixingEntity zhixing = zhixingMapper.selectOne(query);
|
if (zhixing == null) {
|
throw new DataException("未找到文件复审执行记录:f_id=" + zhixingId);
|
}
|
return zhixing;
|
}
|
|
private List<DmsWenjianFushenZhixingZixiangEntity> findZhixingZixiangs(String zhixingId)
|
throws DataException {
|
LambdaQueryWrapper<DmsWenjianFushenZhixingZixiangEntity> query = new LambdaQueryWrapper<>();
|
query.eq(DmsWenjianFushenZhixingZixiangEntity::getForeignId, zhixingId)
|
.isNull(DmsWenjianFushenZhixingZixiangEntity::getDeleteMark);
|
List<DmsWenjianFushenZhixingZixiangEntity> zixiangs = zhixingZixiangMapper.selectList(query);
|
if (zixiangs == null || zixiangs.isEmpty()) {
|
throw new DataException("未找到文件复审执行子项:f_foreign_id=" + zhixingId);
|
}
|
return zixiangs;
|
}
|
|
private void writeBackZixiang(DmsWenjianFushenZhixingEntity zhixing,
|
DmsWenjianFushenZhixingZixiangEntity zhixingZixiang, String fenpeiZixiangId) throws DataException {
|
LambdaUpdateWrapper<DmsWenjianFushenJihuaFenpeiZixiangEntity> update = new LambdaUpdateWrapper<>();
|
update.eq(DmsWenjianFushenJihuaFenpeiZixiangEntity::getId, fenpeiZixiangId)
|
.isNull(DmsWenjianFushenJihuaFenpeiZixiangEntity::getDeleteMark)
|
.set(DmsWenjianFushenJihuaFenpeiZixiangEntity::getHuiguRiqi, zhixing.getHuiguRiqi())
|
.set(DmsWenjianFushenJihuaFenpeiZixiangEntity::getHuiguNeirongZongjie,
|
zhixingZixiang.getHuiguNeirongZongjie())
|
.set(DmsWenjianFushenJihuaFenpeiZixiangEntity::getZuizhongJielun,
|
zhixingZixiang.getZuizhongJielun())
|
.set(DmsWenjianFushenJihuaFenpeiZixiangEntity::getBizStatus, "yiwancheng");
|
if (zixiangMapper.update(null, update) != 1) {
|
throw new DataException("未找到可回写的文件复审计划分配子项:f_id=" + fenpeiZixiangId);
|
}
|
}
|
|
private Set<String> resolveZixiangIds(List<DmsWenjianFushenZhixingBatchReturnForm> forms)
|
throws DataException {
|
if (forms == null || forms.isEmpty()) {
|
throw new DataException("文件复审执行批量退回参数不能为空");
|
}
|
Set<String> ids = new LinkedHashSet<>();
|
for (DmsWenjianFushenZhixingBatchReturnForm form : forms) {
|
if (form == null) {
|
throw new DataException("文件复审执行批量退回参数中不能包含空记录");
|
}
|
String id = requireValue(form.getFenpeiZixiangId(), "fenpei_zixiang_id");
|
if (!ids.add(id)) {
|
throw new DataException("文件复审执行批量退回参数中不能包含重复fenpei_zixiang_id");
|
}
|
}
|
return ids;
|
}
|
|
private String requireValue(String value, String fieldName) throws DataException {
|
String result = trimToNull(value);
|
if (result == null) {
|
throw new DataException(fieldName + "不能为空");
|
}
|
return result;
|
}
|
|
private static class ReviewExtension {
|
private final String wenjianId;
|
private final Date effectiveTo;
|
|
private ReviewExtension(String wenjianId, Date effectiveTo) {
|
this.wenjianId = wenjianId;
|
this.effectiveTo = effectiveTo;
|
}
|
}
|
}
|