package com.ruoyi.approve.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.ruoyi.approve.enums.ApproveType;
|
import com.ruoyi.approve.mapper.ApproveFlowDefinitionMapper;
|
import com.ruoyi.approve.mapper.ApproveFlowNodeDefinitionMapper;
|
import com.ruoyi.approve.mapper.ApproveNodeMapper;
|
import com.ruoyi.approve.mapper.ApproveProcessMapper;
|
import com.ruoyi.approve.pojo.ApproveFlowDefinition;
|
import com.ruoyi.approve.pojo.ApproveFlowNodeDefinition;
|
import com.ruoyi.approve.pojo.ApproveNode;
|
import com.ruoyi.approve.pojo.ApproveProcess;
|
import com.ruoyi.approve.service.IApproveNodeService;
|
import com.ruoyi.approve.service.IApproveProcessService;
|
import com.ruoyi.approve.utils.DailyRedisCounter;
|
import com.ruoyi.approve.vo.ApproveGetAndUpdateVo;
|
import com.ruoyi.approve.vo.ApproveNodeVO;
|
import com.ruoyi.approve.vo.ApproveProcessVO;
|
import com.ruoyi.common.enums.FileNameType;
|
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.other.service.impl.TempFileServiceImpl;
|
import com.ruoyi.project.system.domain.SysDept;
|
import com.ruoyi.project.system.domain.SysUser;
|
import com.ruoyi.project.system.mapper.SysDeptMapper;
|
import com.ruoyi.project.system.mapper.SysUserMapper;
|
import com.ruoyi.sales.mapper.CommonFileMapper;
|
import com.ruoyi.sales.mapper.SalesLedgerMapper;
|
import com.ruoyi.sales.pojo.CommonFile;
|
import com.ruoyi.sales.pojo.SalesLedger;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.StringUtils;
|
|
import java.io.IOException;
|
import java.text.ParseException;
|
import java.text.SimpleDateFormat;
|
import java.time.LocalDate;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Date;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.stream.Collectors;
|
|
@Service
|
@RequiredArgsConstructor
|
public class ApproveProcessServiceImpl extends ServiceImpl<ApproveProcessMapper, ApproveProcess> implements IApproveProcessService {
|
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
private final DailyRedisCounter dailyRedisCounter;
|
private final SysDeptMapper sysDeptMapper;
|
private final IApproveNodeService approveNodeService;
|
private final SysUserMapper sysUserMapper;
|
private final ApproveProcessMapper approveProcessMapper;
|
private final ApproveNodeMapper approveNodeMapper;
|
private final TempFileServiceImpl tempFileService;
|
private final CommonFileMapper commonFileMapper;
|
private final SalesLedgerMapper salesLedgerMapper;
|
private final ApproveFlowDefinitionMapper flowDefinitionMapper;
|
private final ApproveFlowNodeDefinitionMapper flowNodeDefinitionMapper;
|
private final ObjectMapper objectMapper;
|
|
@Override
|
public void addApprove(ApproveProcessVO request) throws Exception {
|
if (request == null || request.getApproveType() == null) throw new RuntimeException("审批类型不能为空");
|
ApproveType type = ApproveType.fromCode(request.getApproveType());
|
Long tenantId = tenantId();
|
SysUser applicant = SecurityUtils.getLoginUser().getUser();
|
Long deptId = resolveDeptId(request.getApproveDeptId());
|
SysDept dept = sysDeptMapper.selectDeptById(deptId);
|
if (dept == null) throw new RuntimeException("申请部门不存在");
|
|
List<ApproveNodeVO> nodes = resolveNodes(request, tenantId);
|
List<SysUser> approvers = validateApprovers(nodes, tenantId);
|
prepareBusinessData(request, type, tenantId);
|
|
String approveCode = LocalDate.now().format(DATE_FORMAT)
|
+ String.format("%03d", dailyRedisCounter.incrementAndGetByDb());
|
ApproveProcess process = new ApproveProcess();
|
process.setApproveId(approveCode);
|
process.setApproveUser(applicant.getUserId());
|
process.setApproveUserName(applicant.getNickName());
|
process.setApproveDeptId(deptId);
|
process.setApproveDeptName(dept.getDeptName());
|
process.setApproveUserIds(nodes.stream().map(item -> String.valueOf(item.getUserId())).collect(Collectors.joining(",")));
|
process.setApproveUserNames(approvers.stream().map(SysUser::getNickName).collect(Collectors.joining(",")));
|
process.setApproveTime(parseDate(request.getApproveTime()));
|
process.setApproveReason(request.getApproveReason());
|
process.setApproveStatus(0);
|
process.setApproveDelete(0);
|
process.setApproveType(type.getCode());
|
process.setTenantId(tenantId);
|
process.setBusinessId(request.getBusinessId());
|
process.setBusinessNo(request.getBusinessNo());
|
process.setBusinessTitle(request.getBusinessTitle());
|
process.setAmount(request.getAmount());
|
process.setBusinessData(request.getBusinessData());
|
process.setFlowDefinitionId(request.getFlowDefinitionId());
|
process.setCreateTime(LocalDateTime.now());
|
process.setUpdateTime(LocalDateTime.now());
|
approveProcessMapper.insert(process);
|
approveNodeService.initApproveNodes(nodes, approveCode, tenantId);
|
tempFileService.migrateTempFilesToFormal(process.getId(), request.getTempFileIds(), FileNameType.ApproveProcess.getValue());
|
}
|
|
private void prepareBusinessData(ApproveProcessVO request, ApproveType type, Long tenantId) throws JsonProcessingException {
|
if (type == ApproveType.SALES_CONTRACT) {
|
if (request.getBusinessId() == null) throw new RuntimeException("请选择销售合同");
|
SalesLedger ledger = salesLedgerMapper.selectById(request.getBusinessId());
|
if (ledger == null || !tenantId.equals(ledger.getTenantId())) throw new RuntimeException("销售合同不存在或不属于当前租户");
|
Long duplicate = approveProcessMapper.selectCount(new LambdaQueryWrapper<ApproveProcess>()
|
.eq(ApproveProcess::getTenantId, tenantId)
|
.eq(ApproveProcess::getApproveType, ApproveType.SALES_CONTRACT.getCode())
|
.eq(ApproveProcess::getBusinessId, ledger.getId())
|
.in(ApproveProcess::getApproveStatus, Arrays.asList(0, 1))
|
.eq(ApproveProcess::getApproveDelete, 0));
|
if (duplicate != null && duplicate > 0) throw new RuntimeException("该销售合同已有待审流程");
|
Map<String, Object> snapshot = new LinkedHashMap<>();
|
snapshot.put("salesLedgerId", ledger.getId());
|
snapshot.put("salesContractNo", ledger.getSalesContractNo());
|
snapshot.put("customerContractNo", ledger.getCustomerContractNo());
|
snapshot.put("customerName", ledger.getCustomerName());
|
snapshot.put("projectName", ledger.getProjectName());
|
snapshot.put("salesman", ledger.getSalesman());
|
snapshot.put("contractAmount", ledger.getContractAmount());
|
snapshot.put("executionDate", ledger.getExecutionDate());
|
snapshot.put("paymentMethod", ledger.getPaymentMethod());
|
snapshot.put("remarks", ledger.getRemarks());
|
request.setBusinessNo(ledger.getSalesContractNo());
|
request.setBusinessTitle(StringUtils.hasText(request.getBusinessTitle())
|
? request.getBusinessTitle() : "销售合同审批-" + ledger.getSalesContractNo());
|
request.setAmount(ledger.getContractAmount());
|
request.setBusinessData(objectMapper.writeValueAsString(snapshot));
|
} else if (type == ApproveType.PURCHASE_PLAN || type == ApproveType.FREE_COLLABORATION) {
|
if (!StringUtils.hasText(request.getBusinessTitle())) throw new RuntimeException("审批标题不能为空");
|
if (type == ApproveType.PURCHASE_PLAN && request.getAmount() == null) throw new RuntimeException("采购预算金额不能为空");
|
if (!StringUtils.hasText(request.getBusinessNo())) {
|
String prefix = type == ApproveType.PURCHASE_PLAN ? "CG" : "XT";
|
request.setBusinessNo(prefix + LocalDate.now().format(DATE_FORMAT)
|
+ String.format("%03d", dailyRedisCounter.incrementAndGetByDb()));
|
}
|
}
|
}
|
|
private List<ApproveNodeVO> resolveNodes(ApproveProcessVO request, Long tenantId) {
|
if (!CollectionUtils.isEmpty(request.getNodes())) return request.getNodes();
|
if (request.getFlowDefinitionId() != null) {
|
ApproveFlowDefinition definition = flowDefinitionMapper.selectOne(new LambdaQueryWrapper<ApproveFlowDefinition>()
|
.eq(ApproveFlowDefinition::getId, request.getFlowDefinitionId())
|
.eq(ApproveFlowDefinition::getTenantId, tenantId)
|
.eq(ApproveFlowDefinition::getApproveType, request.getApproveType())
|
.eq(ApproveFlowDefinition::getEnabled, 1)
|
.eq(ApproveFlowDefinition::getDeleteFlag, 0));
|
if (definition == null) throw new RuntimeException("审批流程定义不存在或已停用");
|
List<ApproveFlowNodeDefinition> definitions = flowNodeDefinitionMapper.selectList(
|
new LambdaQueryWrapper<ApproveFlowNodeDefinition>()
|
.eq(ApproveFlowNodeDefinition::getFlowDefinitionId, definition.getId())
|
.eq(ApproveFlowNodeDefinition::getTenantId, tenantId)
|
.eq(ApproveFlowNodeDefinition::getDeleteFlag, 0)
|
.orderByAsc(ApproveFlowNodeDefinition::getNodeOrder));
|
List<ApproveNodeVO> result = new ArrayList<>();
|
for (ApproveFlowNodeDefinition item : definitions) {
|
if (!"USER".equals(item.getApproverType()) || !StringUtils.hasText(item.getApproverValue())) {
|
throw new RuntimeException("当前预设流程包含尚未指定的审批人");
|
}
|
ApproveNodeVO node = new ApproveNodeVO();
|
node.setUserId(Long.valueOf(item.getApproverValue().split(",")[0].trim()));
|
node.setNodeName(item.getNodeName());
|
node.setConditionField(item.getConditionField());
|
node.setConditionOperator(item.getConditionOperator());
|
node.setConditionValue(item.getConditionValue());
|
result.add(node);
|
}
|
if (!result.isEmpty()) return result;
|
}
|
if (!StringUtils.hasText(request.getApproveUserIds())) throw new RuntimeException("请选择审批人");
|
List<ApproveNodeVO> result = new ArrayList<>();
|
for (String id : request.getApproveUserIds().split(",")) {
|
ApproveNodeVO node = new ApproveNodeVO();
|
node.setUserId(Long.valueOf(id.trim()));
|
node.setConditionOperator("ALWAYS");
|
result.add(node);
|
}
|
return result;
|
}
|
|
private List<SysUser> validateApprovers(List<ApproveNodeVO> nodes, Long tenantId) {
|
List<SysUser> users = new ArrayList<>();
|
for (ApproveNodeVO node : nodes) {
|
SysUser user = sysUserMapper.selectUserById(node.getUserId());
|
if (user == null || !tenantId.equals(user.getTenantId())) throw new RuntimeException("审批人不存在或不属于当前租户");
|
users.add(user);
|
}
|
return users;
|
}
|
|
@Override
|
public List<SysDept> selectDeptListByDeptIds(Long[] deptIds) {
|
List<SysDept> departments = new ArrayList<>();
|
if (deptIds == null) return departments;
|
for (Long deptId : deptIds) {
|
SysDept dept = sysDeptMapper.selectDeptById(deptId);
|
if (dept != null) departments.add(dept);
|
}
|
return departments;
|
}
|
|
@Override
|
public IPage<ApproveProcess> listAll(Page page, ApproveProcess request) {
|
request.setTenantId(tenantId());
|
IPage<ApproveProcess> result = approveProcessMapper.listPage(page, request);
|
result.getRecords().forEach(record -> record.setCommonFileList(commonFileMapper.selectList(
|
new LambdaQueryWrapper<CommonFile>()
|
.eq(CommonFile::getCommonId, record.getId())
|
.eq(CommonFile::getType, FileNameType.ApproveProcess.getValue()))));
|
return result;
|
}
|
|
@Override
|
public void delApprove(String[] ids) {
|
if (ids == null) return;
|
for (String code : ids) {
|
ApproveProcess process = findOwnedByCode(code);
|
if (!SecurityUtils.getUserId().equals(process.getApproveUser())) throw new RuntimeException("只能删除本人申请");
|
if (!(Integer.valueOf(0).equals(process.getApproveStatus()) || Integer.valueOf(3).equals(process.getApproveStatus()))) {
|
throw new RuntimeException("审核中的流程不能删除");
|
}
|
UpdateWrapper<ApproveProcess> wrapper = new UpdateWrapper<>();
|
wrapper.lambda().set(ApproveProcess::getApproveDelete, 1)
|
.set(ApproveProcess::getUpdateTime, LocalDateTime.now())
|
.eq(ApproveProcess::getApproveId, code)
|
.eq(ApproveProcess::getTenantId, tenantId());
|
update(wrapper);
|
approveNodeService.delApproveNodeByApproveId(code);
|
}
|
}
|
|
@Override
|
public ApproveProcess getApproveById(String id) {
|
ApproveProcess process = findOwnedByCode(id);
|
process.setCommonFileList(commonFileMapper.selectList(new LambdaQueryWrapper<CommonFile>()
|
.eq(CommonFile::getCommonId, process.getId())
|
.eq(CommonFile::getType, FileNameType.ApproveProcess.getValue())));
|
return process;
|
}
|
|
@Override
|
public void updateByApproveId(ApproveGetAndUpdateVo request) throws IOException {
|
ApproveProcess process = approveProcessMapper.selectOne(new LambdaQueryWrapper<ApproveProcess>()
|
.eq(ApproveProcess::getId, request.getId())
|
.eq(ApproveProcess::getTenantId, tenantId())
|
.eq(ApproveProcess::getApproveDelete, 0));
|
if (process == null) throw new RuntimeException("审批不存在");
|
if (!SecurityUtils.getUserId().equals(process.getApproveUser())) throw new RuntimeException("只能编辑本人申请");
|
if (!(Integer.valueOf(0).equals(process.getApproveStatus()) || Integer.valueOf(3).equals(process.getApproveStatus()))) {
|
throw new RuntimeException("当前审批状态不允许编辑");
|
}
|
process.setApproveReason(request.getApproveReason());
|
process.setBusinessTitle(request.getBusinessTitle());
|
process.setAmount(request.getAmount());
|
process.setBusinessData(request.getBusinessData());
|
process.setUpdateTime(LocalDateTime.now());
|
process.setApproveStatus(0);
|
process.setApproveOverTime(null);
|
approveProcessMapper.updateById(process);
|
|
List<ApproveNodeVO> nodes = request.getNodes();
|
if (CollectionUtils.isEmpty(nodes) && StringUtils.hasText(request.getApproveUserIds())) {
|
nodes = new ArrayList<>();
|
for (String id : request.getApproveUserIds().split(",")) {
|
ApproveNodeVO node = new ApproveNodeVO();
|
node.setUserId(Long.valueOf(id.trim()));
|
node.setConditionOperator("ALWAYS");
|
nodes.add(node);
|
}
|
}
|
if (!CollectionUtils.isEmpty(nodes)) {
|
validateApprovers(nodes, tenantId());
|
UpdateWrapper<ApproveNode> oldNodes = new UpdateWrapper<>();
|
oldNodes.lambda().set(ApproveNode::getDeleteFlag, 1)
|
.set(ApproveNode::getIsCurrent, 0)
|
.eq(ApproveNode::getApproveProcessId, process.getApproveId())
|
.eq(ApproveNode::getTenantId, tenantId());
|
approveNodeMapper.update(null, oldNodes);
|
approveNodeService.initApproveNodes(nodes, process.getApproveId(), tenantId());
|
}
|
tempFileService.migrateTempFilesToFormal(process.getId(), request.getTempFileIds(), FileNameType.ApproveProcess.getValue());
|
}
|
|
private ApproveProcess findOwnedByCode(String code) {
|
ApproveProcess process = approveProcessMapper.selectOne(new LambdaQueryWrapper<ApproveProcess>()
|
.eq(ApproveProcess::getApproveId, code)
|
.eq(ApproveProcess::getApproveDelete, 0)
|
.eq(ApproveProcess::getTenantId, tenantId())
|
.last("limit 1"));
|
if (process == null) throw new RuntimeException("审批不存在");
|
return process;
|
}
|
|
private Long resolveDeptId(Long requested) {
|
Long[] allowed = SecurityUtils.getDeptId();
|
if (requested == null) return SecurityUtils.getLoginUser().getCurrentDeptId();
|
if (allowed != null && Arrays.asList(allowed).contains(requested)) return requested;
|
Long current = SecurityUtils.getLoginUser().getCurrentDeptId();
|
if (requested.equals(current)) return requested;
|
throw new RuntimeException("无权使用该申请部门");
|
}
|
|
private Date parseDate(String value) throws ParseException {
|
return StringUtils.hasText(value) ? new SimpleDateFormat("yyyy-MM-dd").parse(value) : new Date();
|
}
|
|
private Long tenantId() {
|
return SecurityUtils.getLoginUser().getTenantId();
|
}
|
}
|