| | |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.archive.api.document.ArchiveDocumentApi; |
| | | import cn.iocoder.yudao.module.archive.api.document.dto.ArchiveDocumentCreateReqDTO; |
| | | import cn.iocoder.yudao.module.archive.api.document.dto.ArchiveDocumentRespDTO; |
| | | import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; |
| | | import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; |
| | | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; |
| | |
| | | import cn.iocoder.yudao.module.finance.dal.redis.FinanceNoRedisDAO; |
| | | import cn.iocoder.yudao.module.finance.enums.FinanceReimbursementStatusEnum; |
| | | import cn.iocoder.yudao.module.system.api.storage.StorageAttachmentApi; |
| | | import cn.iocoder.yudao.module.system.api.storage.dto.StorageBlobRespDTO; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.flowable.engine.repository.ProcessDefinition; |
| | |
| | | */ |
| | | public static final String REIMBURSEMENT_RECORD_TYPE = "finance_reimbursement"; |
| | | |
| | | /** 归档来源类型:4-财务(对应 archive 模块 source_type) */ |
| | | private static final Integer ARCHIVE_SOURCE_TYPE_FINANCE = 4; |
| | | |
| | | /** 归档密级:3-保密(财务档案默认保密) */ |
| | | private static final Integer ARCHIVE_SECRET_LEVEL_SECRET = 3; |
| | | |
| | | /** 财务档案分类编码(对应 archive_category.code) */ |
| | | private static final String ARCHIVE_CATEGORY_CODE_FINANCE = "finance"; |
| | | |
| | | @Resource |
| | | private FinanceReimbursementMapper reimbursementMapper; |
| | | @Resource |
| | |
| | | |
| | | @Resource |
| | | private StorageAttachmentApi storageAttachmentApi; |
| | | |
| | | @Resource |
| | | private ArchiveDocumentApi archiveDocumentApi; |
| | | |
| | | @Resource |
| | | private BpmProcessInstanceApi processInstanceApi; |
| | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void archiveReimbursement(Long id) { |
| | | // 1. 校验存在 + 已通过状态 |
| | | public String archiveReimbursement(Long id) { |
| | | // 1. 校验存在 + 状态 |
| | | FinanceReimbursementDO reimbursement = validateReimbursementExists(id); |
| | | if (!FinanceReimbursementStatusEnum.APPROVED.getStatus().equals(reimbursement.getStatus())) { |
| | | throw exception(REIMBURSEMENT_ARCHIVE_FAIL_STATUS); |
| | | boolean archived = FinanceReimbursementStatusEnum.ARCHIVED.getStatus().equals(reimbursement.getStatus()); |
| | | if (archived && reimbursement.getArchiveDocumentId() != null) { |
| | | throw exception(REIMBURSEMENT_ALREADY_ARCHIVED, reimbursement.getNo(), |
| | | StrUtil.blankToDefault(archiveNo(id), "未知")); |
| | | } |
| | | if (!archived && !FinanceReimbursementStatusEnum.APPROVED.getStatus().equals(reimbursement.getStatus())) { |
| | | throw exception(REIMBURSEMENT_ARCHIVE_FAIL_STATUS, reimbursement.getNo(), |
| | | FinanceReimbursementStatusEnum.nameOf(reimbursement.getStatus())); |
| | | } |
| | | |
| | | // 2. 更新为已归档 |
| | | // 2. 更新为已归档(历史已归档但尚未生成档案条目的,跳过状态更新,仅补生成档案) |
| | | if (!archived) { |
| | | reimbursementMapper.updateById(new FinanceReimbursementDO() |
| | | .setId(id) |
| | | .setStatus(FinanceReimbursementStatusEnum.ARCHIVED.getStatus()) |
| | | .setArchiveTime(LocalDateTime.now())); |
| | | } |
| | | |
| | | // 3. 按来源单据生成档案条目(财务档案默认「保密」级),并回写档案 ID |
| | | List<Long> blobIds = storageAttachmentApi.listAttachments(REIMBURSEMENT_RECORD_TYPE, id).stream() |
| | | .map(StorageBlobRespDTO::getId).collect(Collectors.toList()); |
| | | Long archiveDocumentId = archiveDocumentApi.archiveBySource(new ArchiveDocumentCreateReqDTO() |
| | | .setSourceType(ARCHIVE_SOURCE_TYPE_FINANCE) |
| | | .setSourceId(id) |
| | | .setSourceNo(reimbursement.getNo()) |
| | | .setSourceTitle(reimbursement.getTitle()) |
| | | .setCategoryCode(ARCHIVE_CATEGORY_CODE_FINANCE) |
| | | .setSecretLevel(ARCHIVE_SECRET_LEVEL_SECRET) |
| | | .setSummary("财务报销凭证归档") |
| | | .setBlobIds(blobIds)).getCheckedData(); |
| | | |
| | | reimbursementMapper.updateById(new FinanceReimbursementDO() |
| | | .setId(id) |
| | | .setStatus(FinanceReimbursementStatusEnum.ARCHIVED.getStatus()) |
| | | .setArchiveTime(LocalDateTime.now())); |
| | | .setArchiveDocumentId(archiveDocumentId)); |
| | | return StrUtil.blankToDefault(archiveNo(id), "未知"); |
| | | } |
| | | |
| | | @Override |
| | |
| | | return reimbursement; |
| | | } |
| | | |
| | | /** 查询来源单据已生成的档案编号(未归档时返回 null) */ |
| | | private String archiveNo(Long reimbursementId) { |
| | | ArchiveDocumentRespDTO archive = archiveDocumentApi |
| | | .getBySource(ARCHIVE_SOURCE_TYPE_FINANCE, reimbursementId).getCheckedData(); |
| | | return archive != null ? archive.getNo() : null; |
| | | } |
| | | |
| | | /** |
| | | * 解析新增时的报销单号:去掉首尾空格后若为空,则由系统按 BX + 日期 + 6 位流水生成, |
| | | * 否则使用用户自定义单号。 |