|
|
|
|
@ -1,5 +1,6 @@
|
|
|
|
|
package org.dromara.oa.erp.service.impl;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
|
|
|
import cn.hutool.core.convert.Convert;
|
|
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
import com.github.yulichang.toolkit.JoinWrappers;
|
|
|
|
|
@ -11,6 +12,7 @@ import org.apache.seata.spring.annotation.GlobalTransactional;
|
|
|
|
|
import org.dromara.common.core.enums.BusinessStatusEnum;
|
|
|
|
|
import org.dromara.common.core.enums.OAStatusEnum;
|
|
|
|
|
import org.dromara.common.core.exception.ServiceException;
|
|
|
|
|
import org.dromara.common.core.utils.DateUtils;
|
|
|
|
|
import org.dromara.common.core.utils.MapstructUtils;
|
|
|
|
|
import org.dromara.common.core.utils.StringUtils;
|
|
|
|
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
|
|
@ -34,6 +36,7 @@ import org.springframework.context.event.EventListener;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
@ -48,6 +51,18 @@ import java.util.stream.Collectors;
|
|
|
|
|
@Slf4j
|
|
|
|
|
public class ErpProjectPurchaseServiceImpl implements IErpProjectPurchaseService {
|
|
|
|
|
|
|
|
|
|
private static final String MATERIAL_DATE_FORMAT = "yyyy-MM-dd";
|
|
|
|
|
|
|
|
|
|
private static final String NODE_PURCHASE_MANAGER = "采购经理";
|
|
|
|
|
|
|
|
|
|
private static final String NODE_PROJECT_MANAGER = "项目经理";
|
|
|
|
|
|
|
|
|
|
private static final String NODE_CHARGE = "部门经理";
|
|
|
|
|
|
|
|
|
|
private static final String NODE_DEPUTY = "副总审核";
|
|
|
|
|
|
|
|
|
|
private static final String NODE_GENERAL_MANAGER = "总经理";
|
|
|
|
|
|
|
|
|
|
private final ErpProjectPurchaseMapper baseMapper;
|
|
|
|
|
|
|
|
|
|
private final ErpProjectPurchaseMaterialMapper purchaseMaterialMapper;
|
|
|
|
|
@ -327,6 +342,198 @@ public class ErpProjectPurchaseServiceImpl implements IErpProjectPurchaseService
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Map<String, Object> buildApprovalWordExportData(Long projectPurchaseId) {
|
|
|
|
|
ErpProjectPurchaseVo purchase = queryById(projectPurchaseId);
|
|
|
|
|
if (purchase == null) {
|
|
|
|
|
throw new ServiceException("项目采购单不存在,ID:" + projectPurchaseId);
|
|
|
|
|
}
|
|
|
|
|
if (!OAStatusEnum.COMPLETED.getStatus().equals(purchase.getProjectPurchaseStatus())) {
|
|
|
|
|
throw new ServiceException("仅项目采购状态为“审批完成”时允许导出采购审批单");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Map<String, Object> data = new HashMap<>(32);
|
|
|
|
|
data.put("采购编号", strVal(purchase.getPurchaseCode()));
|
|
|
|
|
data.put("项目号", strVal(purchase.getProjectCode()));
|
|
|
|
|
data.put("项目名称", strVal(purchase.getProjectName()));
|
|
|
|
|
data.put("项目经理", strVal(purchase.getManagerName()));
|
|
|
|
|
data.put("部门负责人", strVal(purchase.getChargeName()));
|
|
|
|
|
data.put("分管副总", strVal(purchase.getDeputyName()));
|
|
|
|
|
data.put("收货人", strVal(purchase.getConsigneeUser()));
|
|
|
|
|
data.put("收货地址", strVal(purchase.getConsigneeAddress()));
|
|
|
|
|
data.put("收货人联系方式", strVal(purchase.getConsigneeContact()));
|
|
|
|
|
|
|
|
|
|
List<ErpProjectPurchaseMaterialVo> materials = purchase.getPurchaseMaterialList();
|
|
|
|
|
if (materials == null) {
|
|
|
|
|
materials = Collections.emptyList();
|
|
|
|
|
}
|
|
|
|
|
data.put("标准物料", buildMaterialLoopData(materials, "1"));
|
|
|
|
|
data.put("非标准物料", buildMaterialLoopData(materials, "2"));
|
|
|
|
|
|
|
|
|
|
Map<String, Object> flowData = remoteWorkflowService.flowHisTaskList(String.valueOf(projectPurchaseId));
|
|
|
|
|
List<Map<String, Object>> handledTasks = extractHandledTasks(flowData == null ? null : flowData.get("list"));
|
|
|
|
|
data.put("采购经理意见", resolveApprovalOpinion(findLatestTaskByNodeName(handledTasks, NODE_PURCHASE_MANAGER)));
|
|
|
|
|
data.put("项目经理审批意见", resolveApprovalOpinion(findLatestTaskByNodeName(handledTasks, NODE_PROJECT_MANAGER)));
|
|
|
|
|
data.put("部门负责人审批意见", resolveApprovalOpinion(findLatestTaskByNodeName(handledTasks, NODE_CHARGE)));
|
|
|
|
|
data.put("分管副总审批意见", resolveApprovalOpinion(findLatestTaskByNodeName(handledTasks, NODE_DEPUTY)));
|
|
|
|
|
data.put("总经理意见", resolveApprovalOpinion(findLatestTaskByNodeName(handledTasks, NODE_GENERAL_MANAGER)));
|
|
|
|
|
data.put("是否需要总经理审批", resolveNeedGeneralManagerApproval(handledTasks, flowData));
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<Map<String, Object>> buildMaterialLoopData(List<ErpProjectPurchaseMaterialVo> materials, String materialFlag) {
|
|
|
|
|
List<Map<String, Object>> rows = materials.stream()
|
|
|
|
|
.filter(m -> materialFlag.equals(m.getMaterialFlag()))
|
|
|
|
|
.map(this::toMaterialLoopRow)
|
|
|
|
|
.collect(Collectors.toCollection(ArrayList::new));
|
|
|
|
|
if (rows.isEmpty()) {
|
|
|
|
|
rows.add(toEmptyMaterialLoopRow());
|
|
|
|
|
}
|
|
|
|
|
return rows;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Map<String, Object> toMaterialLoopRow(ErpProjectPurchaseMaterialVo material) {
|
|
|
|
|
String name = strVal(material.getMaterialName());
|
|
|
|
|
if (StringUtils.isBlank(name)) {
|
|
|
|
|
name = strVal(material.getPurchaseMaterialName());
|
|
|
|
|
}
|
|
|
|
|
String qty = "";
|
|
|
|
|
if (material.getPurchaseAmount() != null) {
|
|
|
|
|
qty = material.getPurchaseAmount().stripTrailingZeros().toPlainString();
|
|
|
|
|
}
|
|
|
|
|
Map<String, Object> row = new HashMap<>(8);
|
|
|
|
|
row.put("materialName", name);
|
|
|
|
|
row.put("materialCode", strVal(material.getMaterialCode()));
|
|
|
|
|
row.put("specificationDescription", strVal(material.getSpecificationDescription()));
|
|
|
|
|
row.put("unitName", strVal(material.getUnitName()));
|
|
|
|
|
row.put("quantity", qty);
|
|
|
|
|
row.put("arrivalTime", formatMaterialDate(material.getArrivalTime()));
|
|
|
|
|
return row;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Map<String, Object> toEmptyMaterialLoopRow() {
|
|
|
|
|
Map<String, Object> row = new HashMap<>(8);
|
|
|
|
|
row.put("materialName", "");
|
|
|
|
|
row.put("materialCode", "");
|
|
|
|
|
row.put("specificationDescription", "");
|
|
|
|
|
row.put("unitName", "");
|
|
|
|
|
row.put("quantity", "");
|
|
|
|
|
row.put("arrivalTime", "");
|
|
|
|
|
return row;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String resolveNeedGeneralManagerApproval(List<Map<String, Object>> handledTasks, Map<String, Object> flowData) {
|
|
|
|
|
if (findLatestTaskByNodeName(handledTasks, NODE_GENERAL_MANAGER) != null) {
|
|
|
|
|
return "是";
|
|
|
|
|
}
|
|
|
|
|
Object instanceId = flowData == null ? null : flowData.get("instanceId");
|
|
|
|
|
if (instanceId != null) {
|
|
|
|
|
try {
|
|
|
|
|
Map<String, Object> variables = remoteWorkflowService.instanceVariable(Convert.toLong(instanceId));
|
|
|
|
|
if (variables != null) {
|
|
|
|
|
for (String key : List.of("needGmApproval", "needGeneralManager", "generalManagerApproval", "gmApproval")) {
|
|
|
|
|
Object val = variables.get(key);
|
|
|
|
|
if (val != null) {
|
|
|
|
|
return Boolean.TRUE.equals(val) || "1".equals(String.valueOf(val)) || "true".equalsIgnoreCase(String.valueOf(val)) ? "是" : "否";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.warn("读取项目采购流程变量失败, instanceId={}", instanceId, e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return "否";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String resolveApprovalOpinion(Map<String, Object> task) {
|
|
|
|
|
if (task == null) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
String message = strVal(task.get("message"));
|
|
|
|
|
return StringUtils.isNotBlank(message) ? message : "同意";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<Map<String, Object>> extractHandledTasks(Object listObj) {
|
|
|
|
|
if (!(listObj instanceof List<?> taskList) || taskList.isEmpty()) {
|
|
|
|
|
return Collections.emptyList();
|
|
|
|
|
}
|
|
|
|
|
List<Map<String, Object>> handledTasks = new ArrayList<>();
|
|
|
|
|
for (Object taskObj : taskList) {
|
|
|
|
|
Map<String, Object> taskMap = toMap(taskObj);
|
|
|
|
|
if (!taskMap.isEmpty() && taskMap.get("updateTime") != null) {
|
|
|
|
|
handledTasks.add(taskMap);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
handledTasks.sort(Comparator.comparing(task -> {
|
|
|
|
|
Date updateTime = parseDate(task.get("updateTime"));
|
|
|
|
|
return updateTime == null ? new Date(0L) : updateTime;
|
|
|
|
|
}));
|
|
|
|
|
return handledTasks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Map<String, Object> findLatestTaskByNodeName(List<Map<String, Object>> handledTasks, String nodeName) {
|
|
|
|
|
if (StringUtils.isBlank(nodeName) || handledTasks == null || handledTasks.isEmpty()) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
for (int i = handledTasks.size() - 1; i >= 0; i--) {
|
|
|
|
|
Map<String, Object> task = handledTasks.get(i);
|
|
|
|
|
String taskNodeName = strVal(task.get("nodeName"));
|
|
|
|
|
String targetNodeName = strVal(task.get("targetNodeName"));
|
|
|
|
|
if (nodeName.equals(taskNodeName) || nodeName.equals(targetNodeName)) {
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Map<String, Object> toMap(Object obj) {
|
|
|
|
|
if (obj == null) {
|
|
|
|
|
return Collections.emptyMap();
|
|
|
|
|
}
|
|
|
|
|
if (obj instanceof Map<?, ?> rawMap) {
|
|
|
|
|
Map<String, Object> result = new HashMap<>(rawMap.size());
|
|
|
|
|
for (Map.Entry<?, ?> entry : rawMap.entrySet()) {
|
|
|
|
|
result.put(String.valueOf(entry.getKey()), entry.getValue());
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
return BeanUtil.beanToMap(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Date parseDate(Object rawDate) {
|
|
|
|
|
if (rawDate == null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if (rawDate instanceof Date date) {
|
|
|
|
|
return date;
|
|
|
|
|
}
|
|
|
|
|
if (rawDate instanceof Number number) {
|
|
|
|
|
long millis = number.longValue();
|
|
|
|
|
if (String.valueOf(millis).length() == 10) {
|
|
|
|
|
millis = millis * 1000;
|
|
|
|
|
}
|
|
|
|
|
return new Date(millis);
|
|
|
|
|
}
|
|
|
|
|
return DateUtils.parseDate(rawDate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String formatMaterialDate(Date date) {
|
|
|
|
|
if (date == null) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
return DateUtils.parseDateToStr(MATERIAL_DATE_FORMAT, date);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String strVal(Object value) {
|
|
|
|
|
if (value == null) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
if (value instanceof BigDecimal decimal) {
|
|
|
|
|
return decimal.stripTrailingZeros().toPlainString();
|
|
|
|
|
}
|
|
|
|
|
return String.valueOf(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 项目采购流程事件监听
|
|
|
|
|
*
|
|
|
|
|
|