package jnpf.dmsService.impl;
|
|
import jnpf.base.ActionResult;
|
import jnpf.base.BillRuleApi;
|
import jnpf.base.Pagination;
|
import jnpf.base.UserInfo;
|
import jnpf.dmsEntity.fenfa.DmsWenjianDayinJiluEntity;
|
import jnpf.dmsEntity.fenfa.DmsWenjianDayinRenwuEntity;
|
import jnpf.dmsEntity.fenfa.DmsWenjianFenfaFanweiEntity;
|
import jnpf.dmsEntity.fenfa.DmsWenjianFenfaRenwuEntity;
|
import jnpf.dmsEntity.fenfa.DmsWenjianHuishouEntity;
|
import jnpf.dmsEntity.fenfa.DmsWenjianHuishouMingxiEntity;
|
import jnpf.dmsEntity.fenfa.form.DmsWenjianBupinghengForm;
|
import jnpf.dmsEntity.fenfa.form.DmsWenjianHuishouForm;
|
import jnpf.dmsEntity.fenfa.form.DmsWenjianHuishouMingxiForm;
|
import jnpf.dmsEntity.fenfa.form.DmsWenjianQianshouFafangForm;
|
import jnpf.dmsEntity.fenfa.vo.DmsWenjianDayinJiluVO;
|
import jnpf.dmsEntity.fenfa.vo.DmsWenjianDayinRenwuVO;
|
import jnpf.dmsEntity.fenfa.vo.DmsWenjianFenfaRenwuVO;
|
import jnpf.dmsEntity.fenfa.vo.DmsWenjianJiaojieXiangqingVO;
|
import jnpf.dmsEntity.fenfa.vo.DmsWenjianHuishouMingxiVO;
|
import jnpf.dmsEntity.fenfa.vo.DmsWenjianHuishouResultVO;
|
import jnpf.dmsEntity.fenfa.vo.DmsWenjianXiaohuiMingxiVO;
|
import jnpf.dmsIntegration.audit.DmsAuditAdapter;
|
import jnpf.dmsIntegration.audit.DmsAuditRequestSignResolver;
|
import jnpf.dmsIntegration.audit.DmsWenjianHuishouAuditEvent;
|
import jnpf.dmsMapper.DmsWenjianFenfaMapper;
|
import jnpf.dmsPermission.DmsCurrentIdentity;
|
import jnpf.dmsService.DmsWenjianFenfaService;
|
import jnpf.dmsService.DmsWenjianHuishouPolicy;
|
import jnpf.exception.DataException;
|
import jnpf.permission.OrganizeApi;
|
import jnpf.permission.UserApi;
|
import jnpf.permission.entity.OrganizeEntity;
|
import jnpf.permission.entity.UserEntity;
|
import jnpf.permission.model.user.UserRelationIds;
|
import jnpf.util.RandomUtil;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.Date;
|
import java.util.HashSet;
|
import java.util.List;
|
import java.util.Set;
|
|
@Service
|
@RequiredArgsConstructor
|
public class DmsWenjianFenfaServiceImpl implements DmsWenjianFenfaService {
|
|
private static final String NEW = "xinzeng";
|
private static final String REVISION = "xiuding";
|
private static final String PENDING_PRINT = "daidayin";
|
private static final String PARTIALLY_PRINTED = "bufendayin";
|
private static final String PRINTED = "yidayin";
|
private static final String CANCELLED = "yiquxiao";
|
private static final String PENDING_ISSUE = "daifafang";
|
private static final String PENDING_RECEIPT = "daiqianshou";
|
private static final String PENDING_RECYCLE = "daihuishou";
|
private static final String PENDING_DESTRUCTION = "daixiaohui";
|
private static final String PENDING_ARCHIVE = "daiguidang";
|
private static final String ARCHIVED = "yiguidang";
|
private static final String DESTROYED = "yixiaohui";
|
private static final String LEGACY_RECYCLED = "yihuishou";
|
private static final String NEW_AUDIT_SOURCE = "wenjian_xinzeng_shenhe";
|
private static final String REVISION_AUDIT_SOURCE = "wenjian_xiuding_shenhe";
|
private static final String PENDING_DISTRIBUTION = "daifafang";
|
private static final String COMPLETED_DISTRIBUTION = "yiwancheng";
|
private static final String AUTO_DISTRIBUTION = "zidongfenfa";
|
private static final String PRINT_BILL_RULE = "wenjianDayinLiushuihao";
|
private static final String DISTRIBUTION_BILL_RULE = "wenjianFenfaBianhao";
|
|
private final DmsCurrentIdentity identity;
|
private final jnpf.dmsService.DmsWenjianChongdaGuard reprintGuard;
|
private final DmsWenjianFenfaMapper mapper;
|
private final BillRuleApi billRuleApi;
|
private final jnpf.dmsService.DmsWenjianDayinHaomaService numbers;
|
private final OrganizeApi organizeApi;
|
private final UserApi userApi;
|
private final DmsAuditAdapter auditAdapter;
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void ensureNewPrintTasks(String tenantId, String auditId, String wenjianId,
|
String creatorUserId) throws DataException {
|
ensurePrintTasks(NEW, NEW_AUDIT_SOURCE, tenantId, auditId, wenjianId, creatorUserId,
|
mapper.selectNewScopes(tenantId, auditId));
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void ensureRevisionPrintTasks(String tenantId, String auditId, String wenjianId,
|
String creatorUserId) throws DataException {
|
ensurePrintTasks(REVISION, REVISION_AUDIT_SOURCE, tenantId, auditId, wenjianId,
|
creatorUserId,
|
mapper.selectRevisionScopes(tenantId, auditId));
|
}
|
|
private void ensurePrintTasks(String auditType, String sourceType, String tenantId,
|
String auditId, String fileId, String creatorUserId,
|
List<DmsWenjianFenfaFanweiEntity> scopes) throws DataException {
|
Date now = new Date();
|
String resolvedTenantId = requireText(tenantId, "租户ID不能为空");
|
String resolvedAuditId = requireText(auditId, "审核单ID不能为空");
|
String resolvedFileId = requireText(fileId, "文件ID不能为空");
|
String resolvedCreatorUserId = requireText(creatorUserId, "任务创建人不能为空");
|
DmsWenjianDayinRenwuEntity snapshot = mapper.selectAuditPrintSnapshot(
|
resolvedTenantId, auditType, resolvedAuditId);
|
if (snapshot == null) {
|
throw new DataException("未找到打印任务对应的审核文件快照");
|
}
|
// 新增/修订审核共用:先校验整批分发需求,避免前面的任务已写入后才发现非法数量。
|
for (DmsWenjianFenfaFanweiEntity scope : safe(scopes)) {
|
validateScope(scope);
|
}
|
for (DmsWenjianFenfaFanweiEntity scope : safe(scopes)) {
|
DmsWenjianDayinRenwuEntity printTask = new DmsWenjianDayinRenwuEntity();
|
printTask.setId(RandomUtil.uuId());
|
printTask.setTenantId(resolvedTenantId);
|
printTask.setLaiyuanLeixing(sourceType);
|
printTask.setLaiyuanDanjuId(resolvedAuditId);
|
printTask.setLaiyuanMingxiId(scope.getId());
|
printTask.setWenjianId(resolvedFileId);
|
printTask.setWenjianBianhao(requireText(
|
snapshot.getWenjianBianhao(), "审核文件编号不能为空"));
|
printTask.setWenjianMingcheng(requireText(
|
snapshot.getWenjianMingcheng(), "审核文件名称不能为空"));
|
printTask.setBanbenhao(requireText(snapshot.getBanbenhao(), "审核文件版本不能为空"));
|
printTask.setShenheWanchengRiqi(snapshot.getShenheWanchengRiqi());
|
printTask.setPeixunWanchengRiqi(snapshot.getPeixunWanchengRiqi());
|
printTask.setShengxiaoRiqi(snapshot.getShengxiaoRiqi());
|
printTask.setJieshouBumenId(scope.getBumenId());
|
printTask.setWenjianLeibie(scope.getWenjianLeibie());
|
printTask.setDayinFenshu(requireCopies(scope.getFenshu()));
|
printTask.setBizStatus(PENDING_PRINT);
|
printTask.setCreatorUserId(resolvedCreatorUserId);
|
printTask.setCreatorTime(now);
|
if (mapper.insertPrintTaskIfAbsent(printTask) == 1) numbers.ensureTaskNumbers(resolvedTenantId, printTask, 0);
|
}
|
}
|
|
@Override
|
public List<DmsWenjianDayinRenwuVO> tasks(Pagination pagination, String bizStatus)
|
throws DataException {
|
requirePagination(pagination);
|
String status = trim(bizStatus);
|
if (!status.isEmpty() && !PENDING_PRINT.equals(status)
|
&& !PARTIALLY_PRINTED.equals(status) && !PRINTED.equals(status)
|
&& !CANCELLED.equals(status)) {
|
throw new DataException("打印任务状态无效:" + status);
|
}
|
return mapper.selectTaskPage(identity.tenantId(), pagination, status);
|
}
|
|
@Override
|
public List<DmsWenjianFenfaRenwuVO> distributionTasks(
|
Pagination pagination, String bizStatus) throws DataException {
|
requirePagination(pagination);
|
String status = trim(bizStatus);
|
if (!status.isEmpty() && !PENDING_DISTRIBUTION.equals(status)
|
&& !PENDING_RECEIPT.equals(status)
|
&& !COMPLETED_DISTRIBUTION.equals(status) && !CANCELLED.equals(status)) {
|
throw new DataException("分发任务状态无效:" + status);
|
}
|
return mapper.selectDistributionPage(identity.tenantId(), pagination, status);
|
}
|
|
@Override
|
public List<DmsWenjianFenfaRenwuVO> issueLedger(
|
Pagination pagination, String issueStatus) throws DataException {
|
requirePagination(pagination);
|
String status = trim(issueStatus);
|
if (!status.isEmpty() && !"unissued".equals(status) && !"issued".equals(status)) {
|
throw new DataException("发放状态无效:" + status);
|
}
|
return mapper.selectIssueLedgerPage(identity.tenantId(), pagination, status);
|
}
|
|
@Override
|
public List<DmsWenjianFenfaRenwuVO> receiptLedger(
|
Pagination pagination, String receiptStatus) throws DataException {
|
requirePagination(pagination);
|
String status = trim(receiptStatus);
|
if (!status.isEmpty() && !"pending".equals(status) && !"received".equals(status)) {
|
throw new DataException("签收状态无效:" + status);
|
}
|
return mapper.selectReceiptLedgerPage(identity.tenantId(), pagination, status);
|
}
|
|
@Override
|
public DmsWenjianJiaojieXiangqingVO handoverDetail(String recordId)
|
throws DataException {
|
DmsWenjianJiaojieXiangqingVO detail = mapper.selectHandoverDetail(
|
identity.tenantId(), requireText(recordId, "打印记录ID不能为空"));
|
if (detail == null) {
|
throw new DataException("未找到对应的有效打印记录");
|
}
|
String receivingDepartmentId = trim(detail.getJieshouBumenId());
|
if (!receivingDepartmentId.isEmpty()) {
|
OrganizeEntity organization = organizeApi.getInfoById(receivingDepartmentId);
|
if (organization != null
|
&& receivingDepartmentId.equals(trim(organization.getId()))
|
&& !trim(organization.getOrgNameTree()).isEmpty()) {
|
detail.setJieshouBumen(organization.getOrgNameTree());
|
}
|
}
|
return detail;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public List<DmsWenjianDayinJiluVO> print(String taskId, int copies)
|
throws DataException {
|
if (copies <= 0) {
|
throw new DataException("打印份数必须大于0");
|
}
|
UserInfo user = identity.requireUser();
|
String tenantId = identity.tenantId(user);
|
PrintExecution execution = printCopies(user, tenantId, taskId, copies);
|
return execution.output;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public List<DmsWenjianDayinJiluVO> printReserved(String taskId, int copies,
|
List<jnpf.dmsEntity.fenfa.DmsWenjianDayinHaoma> numbers) throws DataException {
|
UserInfo user = identity.requireUser();
|
String tenant = identity.tenantId(user);
|
DmsWenjianDayinRenwuEntity task = selectPrintableTask(tenant, taskId);
|
if (numbers == null || numbers.size() != copies || copies < 1 || copies > 999
|
|| copies > task.getDayinFenshu() - mapper.countConsumedPrints(tenant, taskId))
|
throw new DataException("冻结号码或打印份数不匹配");
|
this.numbers.requireReservedNumbers(tenant, task, mapper.maxPrintSequence(tenant, taskId), numbers);
|
PrintExecution execution = createPrintRecords(user, tenant, task, copies, numbers);
|
return execution.output;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public List<DmsWenjianDayinJiluVO> printRemaining(List<String> taskIds)
|
throws DataException {
|
if (taskIds == null || taskIds.isEmpty()) {
|
throw new DataException("打印任务不能为空");
|
}
|
List<String> resolvedIds = new ArrayList<>(taskIds.size());
|
Set<String> uniqueIds = new HashSet<>();
|
for (String taskId : taskIds) {
|
String resolvedId = requireText(taskId, "打印任务ID不能为空");
|
if (!uniqueIds.add(resolvedId)) {
|
throw new DataException("打印任务不能重复:" + resolvedId);
|
}
|
resolvedIds.add(resolvedId);
|
}
|
// Stable lock order prevents concurrent batches from deadlocking each other.
|
Collections.sort(resolvedIds);
|
|
UserInfo user = identity.requireUser();
|
String tenantId = identity.tenantId(user);
|
List<DmsWenjianDayinJiluVO> result = new ArrayList<>();
|
List<PrintExecution> executions = new ArrayList<>(resolvedIds.size());
|
for (String taskId : resolvedIds) {
|
DmsWenjianDayinRenwuEntity task = selectPrintableTask(tenantId, taskId);
|
int requiredCopies = task.getDayinFenshu();
|
int printedCopies = mapper.countConsumedPrints(tenantId, task.getId());
|
PrintExecution execution = printCopies(user, tenantId, taskId, requiredCopies - printedCopies);
|
executions.add(execution);
|
result.addAll(execution.output);
|
}
|
return result;
|
}
|
|
private PrintExecution printCopies(
|
UserInfo user, String tenantId, String taskId, int copies) throws DataException {
|
DmsWenjianDayinRenwuEntity task = selectPrintableTask(tenantId, taskId);
|
int requiredCopies = task.getDayinFenshu();
|
int printedCopies = mapper.countConsumedPrints(tenantId, task.getId());
|
int remainingCopies = requiredCopies - printedCopies;
|
if (copies < 1 || copies > 999 || copies > remainingCopies) {
|
throw new DataException("本次打印份数超过剩余份数或无效,剩余:" + remainingCopies);
|
}
|
return createPrintRecords(user, tenantId, task, copies, null);
|
}
|
|
|
private DmsWenjianDayinRenwuEntity selectPrintableTask(String tenantId, String taskId)
|
throws DataException {
|
DmsWenjianDayinRenwuEntity task = mapper.selectPrintTaskForUpdate(
|
tenantId, requireText(taskId, "打印任务ID不能为空"));
|
if (task == null) {
|
throw new DataException("打印任务不存在或已删除");
|
}
|
if (CANCELLED.equals(task.getBizStatus())) {
|
throw new DataException("已取消的打印任务不能打印");
|
}
|
if (!PENDING_PRINT.equals(task.getBizStatus()) && !PARTIALLY_PRINTED.equals(task.getBizStatus())) {
|
throw new DataException("当前打印任务状态不允许打印");
|
}
|
if (task.getDayinFenshu() == null || task.getDayinFenshu() <= 0) {
|
throw new DataException("打印任务份数无效");
|
}
|
return task;
|
}
|
|
private PrintExecution createPrintRecords(
|
UserInfo user, String tenantId, DmsWenjianDayinRenwuEntity task,
|
int copies, List<jnpf.dmsEntity.fenfa.DmsWenjianDayinHaoma> numbers) throws DataException {
|
requireText(task.getJieshouBumenId(), "打印任务未设置接收部门");
|
String printingDepartmentId = trimToNull(user.getOrganizeId());
|
int consumedCopies = mapper.countConsumedPrints(tenantId, task.getId());
|
int sequence = mapper.maxPrintSequence(tenantId, task.getId());
|
Date now = new Date();
|
List<DmsWenjianDayinJiluVO> result = new ArrayList<>(copies);
|
List<DmsWenjianDayinJiluEntity> records = new ArrayList<>(copies);
|
for (int i = 0; i < copies; i++) {
|
jnpf.dmsEntity.fenfa.DmsWenjianDayinHaoma number = numbers == null ? null : numbers.get(i);
|
String serialNumber = number == null ? nextPrintSerialNumber() : number.getSerialNumber();
|
DmsWenjianDayinJiluEntity record = new DmsWenjianDayinJiluEntity();
|
record.setId(RandomUtil.uuId());
|
record.setTenantId(tenantId);
|
record.setDayinRenwuId(task.getId());
|
record.setDayinXuhao(++sequence);
|
record.setDayinLiushuihao(serialNumber);
|
if (number != null) {
|
record.setDayinJishuId(number.getCounterId());
|
record.setDayinJishuXuhao(number.getSequence());
|
record.setDayinJishuLiushuihao(number.getCountSerialNumber());
|
}
|
record.setDayinRenId(user.getUserId());
|
record.setDayinBumenId(printingDepartmentId);
|
record.setDayinShijian(now);
|
record.setBizStatus(PENDING_ISSUE);
|
record.setCreatorUserId(user.getUserId());
|
record.setCreatorTime(now);
|
requireSingleUpdate(mapper.insertPrintRecord(record), "生成打印记录失败");
|
records.add(record);
|
|
DmsWenjianDayinJiluVO vo = new DmsWenjianDayinJiluVO();
|
vo.setId(record.getId());
|
vo.setDayinRenwuId(record.getDayinRenwuId());
|
vo.setDayinXuhao(record.getDayinXuhao());
|
vo.setDayinLiushuihao(serialNumber);
|
vo.setDayinJishuLiushuihao(record.getDayinJishuLiushuihao());
|
vo.setDayinRenId(record.getDayinRenId());
|
vo.setDayinBumenId(record.getDayinBumenId());
|
vo.setDayinShijian(now);
|
vo.setBizStatus(PENDING_ISSUE);
|
result.add(vo);
|
}
|
boolean complete = consumedCopies + copies >= task.getDayinFenshu();
|
requireSingleUpdate(mapper.updateTaskStatus(
|
tenantId, task.getId(), complete ? PRINTED : PARTIALLY_PRINTED, user.getUserId(), now), "更新打印任务状态失败");
|
DmsWenjianFenfaRenwuEntity existingDistribution =
|
mapper.selectDistributionTaskByPrintTaskForUpdate(tenantId, task.getId());
|
if (existingDistribution != null) {
|
if (!PENDING_DISTRIBUTION.equals(existingDistribution.getBizStatus())
|
&& !PENDING_RECEIPT.equals(existingDistribution.getBizStatus())) {
|
throw new DataException("现有分发任务状态不允许追加打印记录");
|
}
|
return new PrintExecution(task, records, null, result, complete);
|
}
|
DmsWenjianFenfaRenwuEntity distributionTask = new DmsWenjianFenfaRenwuEntity();
|
distributionTask.setId(RandomUtil.uuId());
|
distributionTask.setTenantId(tenantId);
|
distributionTask.setDayinRenwuId(task.getId());
|
distributionTask.setFenfaBianhao(nextDistributionNumber());
|
distributionTask.setFafangLeixing(AUTO_DISTRIBUTION);
|
distributionTask.setBizStatus(PENDING_DISTRIBUTION);
|
distributionTask.setCreatorUserId(user.getUserId());
|
distributionTask.setCreatorTime(now);
|
requireSingleUpdate(mapper.insertDistributionTaskIfAbsent(distributionTask),
|
"生成分发任务失败");
|
return new PrintExecution(task, records, distributionTask, result, complete);
|
}
|
|
// DMS 打印审计暂关闭;正式副本、发送控制和分发业务记录仍按原流程保存。
|
|
private static final class PrintExecution {
|
private final DmsWenjianDayinRenwuEntity task;
|
private final List<DmsWenjianDayinJiluEntity> records;
|
private final DmsWenjianFenfaRenwuEntity distributionTask;
|
private final boolean complete;
|
private final List<DmsWenjianDayinJiluVO> output;
|
|
private PrintExecution(DmsWenjianDayinRenwuEntity task,
|
List<DmsWenjianDayinJiluEntity> records,
|
DmsWenjianFenfaRenwuEntity distributionTask,
|
List<DmsWenjianDayinJiluVO> output, boolean complete) {
|
this.task = task;
|
this.records = records;
|
this.complete = complete;
|
this.distributionTask = distributionTask;
|
this.output = output;
|
}
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void handoverByRecordId(String recordId, DmsWenjianQianshouFafangForm form)
|
throws DataException {
|
handover(requireText(recordId, "打印记录ID不能为空"), null, form);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void handoverBySerialNumber(
|
String serialNumber, DmsWenjianQianshouFafangForm form) throws DataException {
|
handover(null, requireText(serialNumber, "打印流水号不能为空"), form);
|
}
|
|
private void handover(String recordId, String serialNumber,
|
DmsWenjianQianshouFafangForm form) throws DataException {
|
UserInfo user = identity.requireUser();
|
String tenantId = identity.tenantId(user);
|
DmsWenjianDayinJiluEntity record = mapper.selectPrintForUpdate(
|
tenantId, recordId, serialNumber);
|
if (record == null) {
|
throw new DataException("未找到对应的有效打印记录");
|
}
|
reprintGuard.requireUnlocked(tenantId, record.getId());
|
DmsWenjianDayinRenwuEntity printTask = mapper.selectPrintTaskForUpdate(
|
tenantId, requireText(record.getDayinRenwuId(), "打印任务ID不能为空"));
|
if (printTask == null) {
|
throw new DataException("分发任务对应的打印任务不存在或已删除");
|
}
|
DmsWenjianFenfaRenwuEntity task = mapper.selectDistributionTaskByPrintTaskForUpdate(
|
tenantId, record.getDayinRenwuId());
|
if (task == null) {
|
throw new DataException("打印记录对应的分发任务不存在或已删除");
|
}
|
if (isPostReceiptStatus(record.getBizStatus())) {
|
return;
|
}
|
if (COMPLETED_DISTRIBUTION.equals(task.getBizStatus())) {
|
throw new DataException("分发任务已完成,但当前打印记录尚未签收");
|
}
|
if (!PENDING_DISTRIBUTION.equals(task.getBizStatus())
|
&& !PENDING_RECEIPT.equals(task.getBizStatus())) {
|
throw new DataException("当前分发任务状态不允许签收/发放");
|
}
|
requireText(printTask.getJieshouBumenId(), "打印任务未设置接收部门");
|
String issuerFormUserId = requireText(form.getBizUserId(), "发放人不能为空");
|
if (!user.getUserId().equals(issuerFormUserId)) {
|
throw new DataException("发放人必须是当前操作人");
|
}
|
String issuerDepartmentId = resolveRelatedDepartment(
|
user.getUserId(), user.getOrganizeId());
|
if (!Boolean.TRUE.equals(user.getIsAdministrator())) {
|
issuerDepartmentId = requireText(
|
issuerDepartmentId, "当前发放人未设置所属部门");
|
}
|
String receiverId = requireText(form.getBizReviewUser(), "接收人不能为空");
|
String signerDepartmentId = resolveUserDepartment(receiverId);
|
String bizSign = requireText(form.getBizSign(), "发放人签名不能为空");
|
String bizReviewSign = requireText(form.getBizReviewSign(), "接收人复核签名不能为空");
|
String remark = trimToNull(form.getBeizhuShuoming());
|
Date now = new Date();
|
requireSingleUpdate(mapper.handoverPrintRecord(
|
tenantId, record.getId(), user.getUserId(), issuerDepartmentId,
|
receiverId, signerDepartmentId, bizSign, bizReviewSign, remark, now),
|
"签收/发放失败");
|
int completed = mapper.completeDistributionTaskHandoverIfFinished(
|
tenantId, task.getId(), printTask.getId(), receiverId,
|
user.getUserId(), issuerDepartmentId, remark, now);
|
if (completed < 0 || completed > 1) {
|
throw new DataException("更新分发任务失败");
|
}
|
}
|
|
private String resolveUserDepartment(String userId) throws DataException {
|
List<UserEntity> users = userApi.getUserName(Collections.singletonList(userId));
|
for (UserEntity user : safe(users)) {
|
if (user != null && userId.equals(trim(user.getId()))) {
|
if (Integer.valueOf(0).equals(user.getEnabledMark())) {
|
throw new DataException("所选签收人不存在或已停用");
|
}
|
return requireText(resolveRelatedDepartment(userId, user.getOrganizeId()),
|
"所选签收人未设置所属部门");
|
}
|
}
|
throw new DataException("所选签收人不存在或已停用");
|
}
|
|
private String resolveRelatedDepartment(String userId, String defaultOrganizationId) {
|
UserRelationIds relationIds = userApi.getUserObjectIdList(userId);
|
List<String> organizationIds = relationIds == null
|
? Collections.emptyList() : safe(relationIds.getOrganize());
|
String defaultId = trim(defaultOrganizationId);
|
for (String organizationId : organizationIds) {
|
if (defaultId.equals(trim(organizationId))) {
|
return defaultId;
|
}
|
}
|
for (String organizationId : organizationIds) {
|
String resolved = trimToNull(organizationId);
|
if (resolved != null) {
|
return resolved;
|
}
|
}
|
return null;
|
}
|
|
@Override
|
public String signerDepartmentId(String userId) throws DataException {
|
return resolveUserDepartment(requireText(userId, "签收人ID不能为空"));
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void registerImbalance(String recordId, DmsWenjianBupinghengForm form)
|
throws DataException {
|
// 旧的单副本入口不能绕过原生登记单据。
|
throw new DataException("请通过文件不平衡登记表单提交,旧登记入口已停用");
|
}
|
|
@Override
|
public DmsWenjianHuishouMingxiVO recycleCandidate(String serialNumber)
|
throws DataException {
|
DmsWenjianHuishouMingxiVO candidate = mapper.selectRecycleCandidateBySerialNumber(
|
identity.tenantId(), requireText(serialNumber, "打印流水号不能为空"));
|
if (candidate == null) {
|
throw new DataException("未找到满足回收条件的有效文件副本");
|
}
|
return candidate;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public DmsWenjianHuishouResultVO recycle(DmsWenjianHuishouForm form)
|
throws DataException {
|
if (form == null) {
|
throw new DataException("回收单不能为空");
|
}
|
String recycleId = RandomUtil.uuId();
|
String signature = requireText(form.getBizSign(), "回收人签名不能为空");
|
List<String> recordIds = recycleRecordIds(form.getHuishouMingxi());
|
UserInfo user = identity.requireUser();
|
String tenantId = identity.tenantId(user);
|
Date now = new Date();
|
|
DmsWenjianHuishouEntity recycle = new DmsWenjianHuishouEntity();
|
recycle.setId(recycleId);
|
recycle.setTenantId(tenantId);
|
recycle.setBizSign(signature);
|
// 此接口只处理转待销毁;确认归档由独立归档接口处理。
|
recycle.setChuliFangshi("xiaohui");
|
recycle.setBeizhuShuoming(trimToNull(form.getBeizhuShuoming()));
|
recycle.setDeleteMark(null);
|
requireSingleUpdate(mapper.insertRecycle(recycle), "保存回收单失败");
|
|
List<DmsWenjianHuishouMingxiVO> records = mapper.selectRecyclePrintsForUpdate(
|
tenantId, recordIds);
|
if (records.size() != recordIds.size()) {
|
throw new DataException("存在不存在或已删除的打印记录,无法回收");
|
}
|
for (DmsWenjianHuishouMingxiVO record : records) {
|
DmsWenjianHuishouPolicy.requireEligible(record);
|
reprintGuard.requireUnlocked(tenantId, record.getDayinJiluId());
|
}
|
requireUpdateCount(mapper.markPrintsRecycled(tenantId, recordIds, user.getUserId(), now),
|
records.size(), "更新打印记录回收状态失败");
|
DmsWenjianHuishouPolicy.completeDistributions(mapper, tenantId, records, user.getUserId(), now);
|
java.util.Map<String, String> beforeStatuses = new java.util.LinkedHashMap<>();
|
for (DmsWenjianHuishouMingxiVO record : records)
|
beforeStatuses.put(record.getDayinJiluId(), record.getBizStatus());
|
List<DmsWenjianHuishouMingxiEntity> recycledDetails = new ArrayList<>(records.size());
|
for (DmsWenjianHuishouMingxiVO record : records) {
|
DmsWenjianHuishouMingxiEntity detail = new DmsWenjianHuishouMingxiEntity();
|
detail.setId(RandomUtil.uuId());
|
detail.setForeignId(recycleId);
|
detail.setTenantId(tenantId);
|
detail.setDayinJiluId(record.getDayinJiluId());
|
detail.setDayinLiushuihao(record.getDayinLiushuihao());
|
detail.setWenjianBianhao(record.getWenjianBianhao());
|
detail.setWenjianMingcheng(record.getWenjianMingcheng());
|
detail.setBanbenhao(record.getBanbenhao());
|
detail.setQianshouBumen(record.getQianshouBumen());
|
detail.setQianshouRen(record.getQianshouRen());
|
detail.setQianshouShijian(record.getQianshouShijian());
|
detail.setHuishouRenId(user.getUserId());
|
detail.setHuishouShijian(now);
|
detail.setDeleteMark(null);
|
requireSingleUpdate(mapper.insertRecycleDetail(detail), "保存回收明细失败");
|
recycledDetails.add(detail);
|
}
|
auditAdapter.recycle(DmsWenjianHuishouAuditEvent.builder()
|
.huishouDanjuId(recycleId)
|
.beizhuShuoming(recycle.getBeizhuShuoming())
|
.huishouRenId(user.getUserId())
|
.huishouShijian(now)
|
.details(recycledDetails)
|
.beforeStatuses(beforeStatuses)
|
.relatedSigns(DmsAuditRequestSignResolver.resolve(
|
Collections.singletonMap("biz_sign", signature)))
|
.build());
|
DmsWenjianHuishouResultVO result = new DmsWenjianHuishouResultVO();
|
result.setId(recycleId);
|
result.setHuishouFenshu(records.size());
|
result.setHuishouShijian(now);
|
result.setRepeated(false);
|
return result;
|
}
|
|
@Override
|
public DmsWenjianXiaohuiMingxiVO destructionCandidate(String serialNumber)
|
throws DataException {
|
DmsWenjianXiaohuiMingxiVO candidate =
|
mapper.selectDestructionCandidateBySerialNumber(
|
identity.tenantId(), requireText(serialNumber, "打印流水号不能为空"));
|
if (candidate == null) {
|
throw new DataException("未找到待销毁的文件副本");
|
}
|
return candidate;
|
}
|
|
private boolean isPostReceiptStatus(String status) {
|
return "yiqianshou".equals(status)
|
|| PENDING_RECYCLE.equals(status)
|
|| PENDING_DESTRUCTION.equals(status)
|
|| PENDING_ARCHIVE.equals(status)
|
|| ARCHIVED.equals(status)
|
|| DESTROYED.equals(status)
|
|| LEGACY_RECYCLED.equals(status);
|
}
|
|
private List<String> recycleRecordIds(List<DmsWenjianHuishouMingxiForm> details)
|
throws DataException {
|
if (details == null || details.isEmpty()) {
|
throw new DataException("至少需要一条待回收明细");
|
}
|
List<String> result = new ArrayList<>(details.size());
|
Set<String> uniqueIds = new HashSet<>();
|
for (DmsWenjianHuishouMingxiForm detail : details) {
|
if (detail == null) {
|
throw new DataException("回收明细不能为空");
|
}
|
String recordId = requireText(detail.getDayinJiluId(), "打印记录ID不能为空");
|
if (!uniqueIds.add(recordId)) {
|
throw new DataException("打印记录不能重复回收:" + recordId);
|
}
|
result.add(recordId);
|
}
|
Collections.sort(result);
|
return result;
|
}
|
|
private void validateScope(DmsWenjianFenfaFanweiEntity scope) throws DataException {
|
if (scope == null) {
|
throw new DataException("分发范围数据为空");
|
}
|
requireText(scope.getId(), "分发范围行ID不能为空");
|
requireText(scope.getBumenId(), "分发部门不能为空");
|
requireText(scope.getWenjianLeibie(), "分发文件类别不能为空");
|
requireCopies(scope.getFenshu());
|
}
|
|
private int requireCopies(Integer value) throws DataException {
|
if (value == null) {
|
throw new DataException("分发份数不能为空");
|
}
|
if (value <= 0) {
|
throw new DataException("分发份数必须大于0:" + value);
|
}
|
return value;
|
}
|
|
private String nextPrintSerialNumber() throws DataException {
|
ActionResult<String> result = billRuleApi.getBillNumber(PRINT_BILL_RULE);
|
String number = result == null ? null : trim(result.getData());
|
if (number == null || number.isEmpty()) {
|
throw new DataException("打印流水号取号失败:单据规则["
|
+ PRINT_BILL_RULE + "]不可用");
|
}
|
return number;
|
}
|
|
private String nextDistributionNumber() throws DataException {
|
ActionResult<String> result = billRuleApi.getBillNumber(DISTRIBUTION_BILL_RULE);
|
String number = result == null ? null : trim(result.getData());
|
if (number == null || number.isEmpty()) {
|
throw new DataException("分发编号取号失败:单据规则["
|
+ DISTRIBUTION_BILL_RULE + "]不可用");
|
}
|
return number;
|
}
|
|
private void requirePagination(Pagination pagination) throws DataException {
|
if (pagination == null || pagination.getCurrentPage() <= 0
|
|| pagination.getPageSize() <= 0) {
|
throw new DataException("分页参数无效");
|
}
|
}
|
|
private void requireSingleUpdate(int count, String message) throws DataException {
|
requireUpdateCount(count, 1, message);
|
}
|
|
private void requireUpdateCount(int count, int expected, String message) throws DataException {
|
if (count != expected) {
|
throw new DataException(message);
|
}
|
}
|
|
private String requireText(String value, String message) throws DataException {
|
String resolved = trim(value);
|
if (resolved.isEmpty()) {
|
throw new DataException(message);
|
}
|
return resolved;
|
}
|
|
private String trim(String value) {
|
return value == null ? "" : value.trim();
|
}
|
|
private String trimToNull(String value) {
|
String resolved = trim(value);
|
return resolved.isEmpty() ? null : resolved;
|
}
|
|
private <T> List<T> safe(List<T> values) {
|
return values == null ? java.util.Collections.<T>emptyList() : values;
|
}
|
}
|