package com.ruoyi.approve.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
|
import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeApproverDto;
|
import com.ruoyi.approve.bean.dto.ApprovalTemplateNodeDto;
|
import com.ruoyi.approve.bean.dto.FinReimbursementDto;
|
import com.ruoyi.approve.bean.vo.FinReimbursementVo;
|
import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
|
import com.ruoyi.approve.mapper.FinReimbursementDetailMapper;
|
import com.ruoyi.approve.mapper.FinReimbursementMapper;
|
import com.ruoyi.approve.mapper.FinReimbursementTravelMapper;
|
import com.ruoyi.approve.pojo.*;
|
import com.ruoyi.basic.enums.ApplicationTypeEnum;
|
import com.ruoyi.basic.enums.RecordTypeEnum;
|
import com.ruoyi.basic.utils.FileUtil;
|
import com.ruoyi.approve.service.*;
|
import com.ruoyi.common.enums.TypeEnums;
|
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.utils.OrderUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.project.system.service.ISysNoticeService;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 报销单主表 服务实现类
|
* </p>
|
*
|
* @author 芯导软件(江苏)有限公司
|
* @since 2026-05-21 09:56:15
|
*/
|
@Service
|
@RequiredArgsConstructor
|
public class FinReimbursementServiceImpl extends ServiceImpl<FinReimbursementMapper, FinReimbursement> implements FinReimbursementService {
|
|
private static final String BILL_STATUS_DRAFT = "DRAFT";
|
private static final String BILL_STATUS_IN_APPROVAL = "IN_APPROVAL";
|
private static final String NODE_STATUS_WAITING = "WAITING";
|
|
private final ApprovalInstanceMapper approvalInstanceMapper;
|
private final ApprovalInstanceService approvalInstanceService;
|
private final ApprovalInstanceNodeService approvalInstanceNodeService;
|
private final ApprovalTaskService approvalTaskService;
|
private final ApprovalRecordService approvalRecordService;
|
private final FinReimbursementMapper finReimbursementMapper;
|
private final FinReimbursementTravelMapper finReimbursementTravelMapper;
|
private final FinReimbursementDetailMapper finReimbursementDetailMapper;
|
private final FileUtil fileUtil;
|
private final ISysNoticeService sysNoticeService;
|
@Override
|
public IPage<FinReimbursementVo> listPage(FinReimbursementDto finReimbursementDto, Page<FinReimbursementVo> page) {
|
IPage<FinReimbursementVo> finReimbursementVoIPage = finReimbursementMapper.listPage(finReimbursementDto, page);
|
finReimbursementVoIPage.getRecords().forEach(vo -> {
|
vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.FIN_REIMBURSEMENT, vo.getId()));
|
});
|
|
return finReimbursementVoIPage;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Boolean add(FinReimbursementDto finReimbursementDto) {
|
String billStatus = validateAddParam(finReimbursementDto);
|
|
// 生成报销单号
|
String billNo = OrderUtils.countTodayByCreateTime(finReimbursementMapper, "BXD", "bill_no");
|
List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
|
BigDecimal totalAmount = details.stream()
|
.map(FinReimbursementDetail::getAmount)
|
.filter(Objects::nonNull)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
FinReimbursement reimbursement = buildReimbursement(finReimbursementDto, billNo, totalAmount, billStatus);
|
// 保存报销单主表
|
boolean saved = this.save(reimbursement);
|
if (!saved || reimbursement.getId() == null) {
|
throw new ServiceException("新增报销单失败");
|
}
|
Long reimbursementId = reimbursement.getId();
|
|
// 保存差旅报销扩展信息(报销类型为差旅报销时)
|
FinReimbursementTravel travel = finReimbursementDto.getTravel();
|
if (isTravelReimbursement(finReimbursementDto.getReimbursementType())) {
|
travel.setReimbursementId(reimbursementId);
|
int travelRows = finReimbursementTravelMapper.insert(travel);
|
if (travelRows != 1) {
|
throw new ServiceException("新增差旅报销扩展信息失败");
|
}
|
}
|
|
// 保存报销单明细
|
for (int i = 0; i < details.size(); i++) {
|
FinReimbursementDetail detail = details.get(i);
|
detail.setId(null);
|
detail.setReimbursementId(reimbursementId);
|
detail.setRowNo(i + 1);
|
int detailRows = finReimbursementDetailMapper.insert(detail);
|
if (detailRows != 1) {
|
throw new ServiceException("新增报销单明细失败");
|
}
|
}
|
|
if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
|
startApproval(reimbursement, finReimbursementDto);
|
}
|
fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, reimbursementId, finReimbursementDto.getStorageBlobDTOs());
|
return true;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Boolean update(FinReimbursementDto finReimbursementDto) {
|
String billStatus = validateUpdateParam(finReimbursementDto);
|
|
Long reimbursementId = finReimbursementDto.getId();
|
FinReimbursement existing = finReimbursementMapper.selectById(reimbursementId);
|
if (existing == null) {
|
throw new ServiceException("报销单不存在");
|
}
|
|
// 计算明细汇总金额
|
List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
|
BigDecimal totalAmount = details.stream()
|
.map(FinReimbursementDetail::getAmount)
|
.filter(Objects::nonNull)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
// 更新主表
|
FinReimbursement reimbursement = buildReimbursement(
|
finReimbursementDto,
|
existing.getBillNo(),
|
totalAmount,
|
billStatus
|
);
|
reimbursement.setId(reimbursementId);
|
int mainRows = finReimbursementMapper.updateById(reimbursement);
|
if (mainRows != 1) {
|
throw new ServiceException("更新报销单主表失败");
|
}
|
|
// 查询数据库中已有的明细
|
List<FinReimbursementDetail> existingDetails = finReimbursementDetailMapper.selectList(
|
new LambdaQueryWrapper<FinReimbursementDetail>()
|
.eq(FinReimbursementDetail::getReimbursementId, reimbursementId));
|
Set<Long> existingDetailIds = existingDetails.stream()
|
.map(FinReimbursementDetail::getId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
|
// 新明细中有ID的 → 更新;无ID的 → 新增
|
Set<Long> submittedDetailIds = new HashSet<>();
|
for (int i = 0; i < details.size(); i++) {
|
FinReimbursementDetail detail = details.get(i);
|
detail.setReimbursementId(reimbursementId);
|
detail.setRowNo(i + 1);
|
if (detail.getId() != null && existingDetailIds.contains(detail.getId())) {
|
finReimbursementDetailMapper.updateById(detail);
|
submittedDetailIds.add(detail.getId());
|
} else {
|
detail.setId(null);
|
finReimbursementDetailMapper.insert(detail);
|
}
|
}
|
|
// 数据库中已有但新明细中没有的 → 删除
|
for (Long existingId : existingDetailIds) {
|
if (!submittedDetailIds.contains(existingId)) {
|
finReimbursementDetailMapper.deleteById(existingId);
|
}
|
}
|
|
// 差旅扩展:有则更新,无则新增
|
FinReimbursementTravel existingTravel = finReimbursementTravelMapper.selectOne(
|
new LambdaQueryWrapper<FinReimbursementTravel>()
|
.eq(FinReimbursementTravel::getReimbursementId, reimbursementId)
|
.last("LIMIT 1"));
|
FinReimbursementTravel travel = finReimbursementDto.getTravel();
|
if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && travel != null) {
|
travel.setReimbursementId(reimbursementId);
|
if (existingTravel != null) {
|
travel.setId(existingTravel.getId());
|
finReimbursementTravelMapper.updateById(travel);
|
} else {
|
travel.setId(null);
|
finReimbursementTravelMapper.insert(travel);
|
}
|
}
|
|
resetApprovalFlow(existing.getApprovalInstanceId(), reimbursementId);
|
if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
|
reimbursement.setApprovalInstanceId(null);
|
startApproval(reimbursement, finReimbursementDto);
|
}
|
fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, reimbursementId, finReimbursementDto.getStorageBlobDTOs());
|
|
return true;
|
}
|
|
@Override
|
public FinReimbursementVo detail(Long id) {
|
if (id == null ) {
|
throw new ServiceException("报销单ID不能为空");
|
}
|
|
FinReimbursement reimbursement = finReimbursementMapper.selectById(id);
|
if (reimbursement == null) {
|
throw new ServiceException("报销单不存在");
|
}
|
|
FinReimbursementVo vo = new FinReimbursementVo();
|
vo.setId(reimbursement.getId());
|
vo.setBillNo(reimbursement.getBillNo());
|
vo.setReimbursementType(reimbursement.getReimbursementType());
|
vo.setExpenseType(reimbursement.getExpenseType());
|
vo.setApplicantId(reimbursement.getApplicantId());
|
vo.setApplicantCode(reimbursement.getApplicantCode());
|
vo.setApplicantName(reimbursement.getApplicantName());
|
vo.setApplicantDeptId(reimbursement.getApplicantDeptId());
|
vo.setApplicantDeptName(reimbursement.getApplicantDeptName());
|
vo.setReason(reimbursement.getReason());
|
vo.setApplyAmount(reimbursement.getApplyAmount());
|
vo.setDetailTotalAmount(reimbursement.getDetailTotalAmount());
|
vo.setPayeeName(reimbursement.getPayeeName());
|
vo.setPayeeAccount(reimbursement.getPayeeAccount());
|
vo.setPayeeBank(reimbursement.getPayeeBank());
|
vo.setApprovalInstanceId(reimbursement.getApprovalInstanceId());
|
vo.setApproveProcessId(reimbursement.getApproveProcessId());
|
vo.setBillStatus(reimbursement.getBillStatus());
|
vo.setApprovedTime(reimbursement.getApprovedTime());
|
vo.setPaidTime(reimbursement.getPaidTime());
|
vo.setAccountExpenseId(reimbursement.getAccountExpenseId());
|
vo.setRemark(reimbursement.getRemark());
|
vo.setTenantId(reimbursement.getTenantId());
|
vo.setCreateUser(reimbursement.getCreateUser());
|
vo.setCreateTime(reimbursement.getCreateTime());
|
vo.setUpdateUser(reimbursement.getUpdateUser());
|
vo.setUpdateTime(reimbursement.getUpdateTime());
|
vo.setDeptId(reimbursement.getDeptId());
|
vo.setDeleted(reimbursement.getDeleted());
|
|
vo.setDetails(finReimbursementDetailMapper.selectList(
|
new LambdaQueryWrapper<FinReimbursementDetail>()
|
.eq(FinReimbursementDetail::getReimbursementId, reimbursement.getId())
|
.orderByAsc(FinReimbursementDetail::getRowNo)
|
));
|
|
if (isTravelReimbursement(reimbursement.getReimbursementType())) {
|
vo.setTravel(finReimbursementTravelMapper.selectOne(
|
new LambdaQueryWrapper<FinReimbursementTravel>()
|
.eq(FinReimbursementTravel::getReimbursementId, reimbursement.getId())
|
.last("LIMIT 1")
|
));
|
}
|
vo.setStorageBlobVOList(fileUtil.getStorageBlobVOsByRecordTypeAndRecordId(RecordTypeEnum.FIN_REIMBURSEMENT, reimbursement.getId()));
|
//审批记录返回
|
vo.setTasks(approvalTaskService.list(new LambdaQueryWrapper<ApprovalTask>().eq(ApprovalTask::getInstanceId, reimbursement.getApprovalInstanceId())));
|
vo.setRecords(approvalRecordService.list(new LambdaQueryWrapper<ApprovalRecord>().eq(ApprovalRecord::getInstanceId, reimbursement.getApprovalInstanceId())));
|
return vo;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Boolean delete(List<Long> ids) {
|
fileUtil.deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum.FILE, RecordTypeEnum.FIN_REIMBURSEMENT, ids);
|
//先删除明细
|
finReimbursementDetailMapper.delete(new LambdaQueryWrapper<FinReimbursementDetail>().in(FinReimbursementDetail::getReimbursementId, ids));
|
//删除差旅
|
finReimbursementTravelMapper.delete(new LambdaQueryWrapper<FinReimbursementTravel>().in(FinReimbursementTravel::getReimbursementId, ids));
|
//删除主表
|
int rows = finReimbursementMapper.delete(new LambdaQueryWrapper<FinReimbursement>().in(FinReimbursement::getId, ids));
|
return rows == ids.size();
|
}
|
|
private String validateUpdateParam(FinReimbursementDto finReimbursementDto) {
|
if (finReimbursementDto == null || finReimbursementDto.getId() == null) {
|
throw new ServiceException("报销单ID不能为空");
|
}
|
if (finReimbursementDto.getReimbursementType() == null) {
|
throw new ServiceException("报销类型不能为空");
|
}
|
String billStatus = normalizeBillStatus(finReimbursementDto.getBillStatus());
|
if (billStatus == null) {
|
throw new ServiceException("单据状态只支持 DRAFT 或 IN_APPROVAL");
|
}
|
if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
|
validateApprovalNodes(finReimbursementDto.getNodes());
|
}
|
List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
|
if (details == null || details.isEmpty()) {
|
throw new ServiceException("报销单明细不能为空");
|
}
|
for (FinReimbursementDetail detail : details) {
|
if (detail == null) {
|
throw new ServiceException("报销单明细不能为空");
|
}
|
if (detail.getAmount() == null || detail.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
|
throw new ServiceException("报销单明细金额必须大于0");
|
}
|
}
|
if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() == null) {
|
throw new ServiceException("差旅报销必须填写差旅扩展信息");
|
}
|
if (!isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() != null) {
|
throw new ServiceException("非差旅报销不允许填写差旅扩展信息");
|
}
|
return billStatus;
|
}
|
|
private String validateAddParam(FinReimbursementDto finReimbursementDto) {
|
if (finReimbursementDto == null) {
|
throw new ServiceException("报销单数据不能为空");
|
}
|
if (finReimbursementDto.getReimbursementType() == null) {
|
throw new ServiceException("报销类型不能为空");
|
}
|
String billStatus = normalizeBillStatus(finReimbursementDto.getBillStatus());
|
if (billStatus == null) {
|
throw new ServiceException("单据状态只支持 DRAFT 或 IN_APPROVAL");
|
}
|
if (BILL_STATUS_IN_APPROVAL.equals(billStatus)) {
|
validateApprovalNodes(finReimbursementDto.getNodes());
|
}
|
List<FinReimbursementDetail> details = finReimbursementDto.getDetails();
|
if (details == null || details.isEmpty()) {
|
throw new ServiceException("报销单明细不能为空");
|
}
|
for (FinReimbursementDetail detail : details) {
|
if (detail == null) {
|
throw new ServiceException("报销单明细不能为空");
|
}
|
if (detail.getAmount() == null || detail.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
|
throw new ServiceException("报销单明细金额必须大于0");
|
}
|
}
|
if (isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() == null) {
|
throw new ServiceException("差旅报销必须填写差旅扩展信息");
|
}
|
if (!isTravelReimbursement(finReimbursementDto.getReimbursementType()) && finReimbursementDto.getTravel() != null) {
|
throw new ServiceException("非差旅报销不允许填写差旅扩展信息");
|
}
|
return billStatus;
|
}
|
|
private FinReimbursement buildReimbursement(FinReimbursementDto finReimbursementDto, String billNo, BigDecimal totalAmount, String billStatus) {
|
FinReimbursement reimbursement = new FinReimbursement();
|
reimbursement.setId(null);
|
reimbursement.setBillNo(billNo);
|
reimbursement.setReimbursementType(finReimbursementDto.getReimbursementType());
|
reimbursement.setExpenseType(finReimbursementDto.getExpenseType());
|
reimbursement.setApplicantId(finReimbursementDto.getApplicantId());
|
reimbursement.setApplicantCode(finReimbursementDto.getApplicantCode());
|
reimbursement.setApplicantName(finReimbursementDto.getApplicantName());
|
reimbursement.setApplicantDeptId(finReimbursementDto.getApplicantDeptId());
|
reimbursement.setApplicantDeptName(finReimbursementDto.getApplicantDeptName());
|
reimbursement.setReason(finReimbursementDto.getReason());
|
reimbursement.setApplyAmount(finReimbursementDto.getApplyAmount());
|
reimbursement.setDetailTotalAmount(totalAmount);
|
reimbursement.setPayeeName(finReimbursementDto.getPayeeName());
|
reimbursement.setPayeeAccount(finReimbursementDto.getPayeeAccount());
|
reimbursement.setPayeeBank(finReimbursementDto.getPayeeBank());
|
reimbursement.setRemark(finReimbursementDto.getRemark());
|
reimbursement.setTenantId(finReimbursementDto.getTenantId());
|
reimbursement.setApproveProcessId(null);
|
reimbursement.setBillStatus(billStatus);
|
return reimbursement;
|
}
|
|
private void startApproval(FinReimbursement reimbursement, FinReimbursementDto finReimbursementDto) {
|
Long businessType = resolveBusinessType(finReimbursementDto.getReimbursementType());
|
ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
|
approvalInstanceDto.setInstanceNo(OrderUtils.countTodayByCreateTime(approvalInstanceMapper, "SP", "instance_no"));
|
approvalInstanceDto.setBusinessId(reimbursement.getId());
|
approvalInstanceDto.setTemplateId(null);
|
approvalInstanceDto.setTemplateName(TypeEnums.getLabelByValue(businessType) + "审批");
|
approvalInstanceDto.setBusinessType(businessType);
|
approvalInstanceDto.setTitle("报销单号:" + reimbursement.getBillNo());
|
approvalInstanceDto.setApplicantId(reimbursement.getApplicantId() != null ? reimbursement.getApplicantId() : SecurityUtils.getUserId());
|
approvalInstanceDto.setApplicantName(reimbursement.getApplicantName() != null ? reimbursement.getApplicantName() : SecurityUtils.getLoginUser().getNickName());
|
approvalInstanceDto.setApplyTime(LocalDateTime.now());
|
approvalInstanceDto.setStatus("PENDING");
|
approvalInstanceDto.setCurrentLevel(1);
|
|
boolean approvalSaved = approvalInstanceService.save(approvalInstanceDto);
|
if (!approvalSaved || approvalInstanceDto.getId() == null) {
|
throw new ServiceException("发起审批失败");
|
}
|
List<ApprovalTask> firstTasks = createApprovalNodes(approvalInstanceDto, finReimbursementDto.getNodes());
|
sendApproveNotice(approvalInstanceDto, firstTasks);
|
|
FinReimbursement update = new FinReimbursement();
|
update.setId(reimbursement.getId());
|
update.setApprovalInstanceId(approvalInstanceDto.getId());
|
update.setBillStatus(BILL_STATUS_IN_APPROVAL);
|
int rows = finReimbursementMapper.updateById(update);
|
if (rows != 1) {
|
throw new ServiceException("回填审批实例失败");
|
}
|
}
|
|
private List<ApprovalTask> createApprovalNodes(ApprovalInstanceDto approvalInstanceDto, List<ApprovalTemplateNodeDto> nodes) {
|
List<ApprovalTask> firstTasks = Collections.emptyList();
|
for (int i = 0; i < nodes.size(); i++) {
|
ApprovalTemplateNodeDto nodeDto = nodes.get(i);
|
ApprovalInstanceNode instanceNode = new ApprovalInstanceNode();
|
instanceNode.setInstanceId(approvalInstanceDto.getId());
|
instanceNode.setLevelNo(nodeDto.getLevelNo());
|
instanceNode.setApproveType(nodeDto.getApproveType());
|
instanceNode.setStatus(i == 0 ? "PENDING" : NODE_STATUS_WAITING);
|
instanceNode.setStartTime(i == 0 ? LocalDateTime.now() : null);
|
instanceNode.setDeleted((byte) 0);
|
approvalInstanceNodeService.save(instanceNode);
|
|
List<ApprovalTask> tasks = nodeDto.getApprovers().stream().map(approver -> {
|
ApprovalTask task = new ApprovalTask();
|
task.setInstanceId(approvalInstanceDto.getId());
|
task.setNodeId(instanceNode.getId());
|
task.setLevelNo(instanceNode.getLevelNo());
|
task.setApproverId(approver.getApproverId());
|
task.setApproverName(approver.getApproverName());
|
task.setTaskStatus("PENDING");
|
task.setIsRead((byte) 0);
|
task.setDeleted((byte) 0);
|
return task;
|
}).collect(Collectors.toList());
|
approvalTaskService.saveBatch(tasks);
|
|
if (i == 0) {
|
firstTasks = tasks;
|
ApprovalRecord record = new ApprovalRecord();
|
record.setInstanceId(approvalInstanceDto.getId());
|
record.setNodeId(instanceNode.getId());
|
record.setOperatorId(approvalInstanceDto.getApplicantId());
|
record.setOperatorName(approvalInstanceDto.getApplicantName());
|
record.setAction("SUBMIT");
|
record.setComment("发起审批");
|
record.setDeleted((byte) 0);
|
approvalRecordService.save(record);
|
}
|
}
|
return firstTasks;
|
}
|
|
private void validateApprovalNodes(List<ApprovalTemplateNodeDto> nodes) {
|
if (nodes == null || nodes.isEmpty()) {
|
throw new ServiceException("提交审批时审批节点不能为空");
|
}
|
for (int i = 0; i < nodes.size(); i++) {
|
ApprovalTemplateNodeDto node = nodes.get(i);
|
if (node == null) {
|
throw new ServiceException("审批节点不能为空");
|
}
|
if (node.getLevelNo() == null) {
|
node.setLevelNo(i + 1);
|
}
|
if (!StringUtils.hasText(node.getApproveType())) {
|
throw new ServiceException("审批节点审批方式不能为空");
|
}
|
List<ApprovalTemplateNodeApproverDto> approvers = node.getApprovers();
|
if (approvers == null || approvers.isEmpty()) {
|
throw new ServiceException("审批节点审批人不能为空");
|
}
|
for (ApprovalTemplateNodeApproverDto approver : approvers) {
|
if (approver == null || approver.getApproverId() == null) {
|
throw new ServiceException("审批人不能为空");
|
}
|
}
|
}
|
}
|
|
private void sendApproveNotice(ApprovalInstanceDto instance, List<ApprovalTask> tasks) {
|
if (instance == null || tasks == null || tasks.isEmpty()) {
|
return;
|
}
|
List<Long> approverIds = tasks.stream()
|
.map(ApprovalTask::getApproverId)
|
.filter(id -> id != null && id > 0)
|
.distinct()
|
.collect(Collectors.toList());
|
if (approverIds.isEmpty()) {
|
return;
|
}
|
String title = "报销审批";
|
String message = "审批单号 " + instance.getInstanceNo() + " 需要您审批";
|
String jumpPath = "/approvalInstance?id=" + instance.getId();
|
sysNoticeService.simpleNoticeByUser(title, message, approverIds, jumpPath);
|
}
|
|
private void resetApprovalFlow(Long approvalInstanceId, Long reimbursementId) {
|
if (approvalInstanceId == null) {
|
return;
|
}
|
approvalInstanceService.delete(Collections.singletonList(approvalInstanceId));
|
int rows = finReimbursementMapper.update(
|
null,
|
Wrappers.<FinReimbursement>lambdaUpdate()
|
.eq(FinReimbursement::getId, reimbursementId)
|
.set(FinReimbursement::getApprovalInstanceId, null)
|
);
|
if (rows != 1) {
|
throw new ServiceException("重置审批流程失败");
|
}
|
}
|
|
private Long resolveBusinessType(Byte reimbursementType) {
|
return isTravelReimbursement(reimbursementType)
|
? TypeEnums.TRAVEL_REIMBURSEMENT_APPROVAL.getCode()
|
: TypeEnums.EXPENSE_APPROVAL.getCode();
|
}
|
|
private String normalizeBillStatus(String billStatus) {
|
if (billStatus == null) {
|
return BILL_STATUS_DRAFT;
|
}
|
String normalized = billStatus.trim().toUpperCase();
|
if (BILL_STATUS_DRAFT.equals(normalized) || BILL_STATUS_IN_APPROVAL.equals(normalized)) {
|
return normalized;
|
}
|
return null;
|
}
|
|
private boolean isTravelReimbursement(Byte reimbursementType) {
|
return Byte.valueOf((byte) 1).equals(reimbursementType);
|
}
|
}
|