工艺日志推送

bom日志推送1
This commit is contained in:
tzy 2025-11-23 21:33:21 +08:00
parent 1a3717d305
commit 6519c24135
9 changed files with 207 additions and 85 deletions

View File

@ -27,7 +27,7 @@
<satoken.version>1.39.0</satoken.version>
<mybatis-plus.version>3.5.3.1</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.18</hutool.version>
<hutool.version>5.8.30</hutool.version>
<okhttp.version>4.10.0</okhttp.version>
<spring-boot-admin.version>2.7.10</spring-boot-admin.version>
<redisson.version>3.20.1</redisson.version>

View File

@ -293,9 +293,10 @@ public class ExcelTemplateProc {
String value = cell.getStringCellValue();
if (value != null) {
String trimmed = value.trim();
for (DynamicDataMapping dynamicData : dynamicDataMappingList) {
if (value.startsWith("{{" + dynamicData.getDataId() + ".")) {
String prefix = "{{" + dynamicData.getDataId() + ".";
if (trimmed.startsWith(prefix) || trimmed.contains(prefix)) {
return dynamicData;
}
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.system.controller;
import java.util.List;
import java.util.Arrays;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
@ -113,6 +114,7 @@ public class PartCostController extends BaseController {
@Log(title = "在金蝶获取成本价", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/getObtainPartData")
@XxlJob("getObtainPartData")
public R<Void> getObtainPartData() {
return toAjax(iPartCostService.getObtainPartData());
}

View File

@ -6,6 +6,7 @@ import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.ruoyi.common.excel.DefaultExcelListener;
@ -17,6 +18,8 @@ import com.ruoyi.common.poi.ExcelTemplateProc;
import com.ruoyi.common.poi.DynamicDataMapping;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.bo.FigureSaveBo;
import com.ruoyi.system.domain.dto.MaterialUseDTO;
import com.ruoyi.system.domain.dto.ProcessRouteDTO;
import com.ruoyi.system.domain.dto.ProcessRouteExcelDTO;
import com.ruoyi.system.domain.dto.ProcessRoutePushResultDTO;
import com.ruoyi.system.domain.vo.*;
@ -542,7 +545,7 @@ public class ProcessOrderProController extends BaseController {
// 使用Excel模板文件
String templatePath = "D:/java/excel-template/生产及工艺计划模版.xlsx";
String templatePath = "jpg/生产及工艺计划模版.xlsx";
String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx";
// 准备模板数据
@ -613,11 +616,11 @@ public class ProcessOrderProController extends BaseController {
List<Map<String, Object>> evoDataList = convertEVOProductsDataToMapList(evoProductsList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("EVOProductsDataVO", evoDataList));
}
// 添加伊特产品数据
/* // 添加伊特产品数据
if (!excelDTOList.isEmpty()) {
List<Map<String, Object>> evoRouteDataList = convertRouteDataToMapList(excelDTOList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessRouteExcelDTO", evoRouteDataList));
}
}*/
// 使用模板导出Excel
ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, outputPath, staticDataMap, dynamicDataMappingList);
@ -625,8 +628,7 @@ public class ProcessOrderProController extends BaseController {
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(orderPro.getProductionOrderNo() + "_分类BOM表", "UTF-8")
.replaceAll("\\+", "%20");
String fileName = URLEncoder.encode(orderPro.getProductionOrderNo() + "_分类BOM表", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 将生成的文件写入响应
@ -671,7 +673,15 @@ public class ProcessOrderProController extends BaseController {
vo.setMaterialCode(getCellValueAsString(row.getCell(0))); // 图号
vo.setMaterialName(getCellValueAsString(row.getCell(1))); // 名称
vo.setMaterial(getCellValueAsString(row.getCell(2))); // 数量
vo.setDiscWeight(getCellValueAsDouble(row.getCell(3))); // 单重
vo.setDiscWeight(getCellValueAsDouble(row.getCell(3)));
vo.setRawMaterialCode(getCellValueAsString(row.getCell(4)));
vo.setRawMaterialName(getCellValueAsString(row.getCell(5)));
vo.setBomMaterial(getCellValueAsString(row.getCell(6)));
vo.setBomUnit(getCellValueAsString(row.getCell(9)));
vo.setBomDanZhong(getCellValueAsDouble(row.getCell(7)));
vo.setDiscUsage(getCellValueAsString(row.getCell(8)));
// 单重
vo.setBatchQuantity(getCellValueAsLong(row.getCell(18))); // 批次数量
vo.setUnitQuantity(getCellValueAsDouble(row.getCell(17))); // 批次数量
@ -1092,10 +1102,10 @@ public class ProcessOrderProController extends BaseController {
/**
* 转换工艺VO为Map列表用于模板
*/
private List<Map<String, Object>> convertRouteDataToMapList(List<ProcessRouteExcelDTO> routeDataList) {
private List<Map<String, Object>> convertRouteDataToMapList(List<ProcessRoute> routeDataList) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (ProcessRouteExcelDTO item : routeDataList) {
for (ProcessRoute item : routeDataList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
map.put("routeDescription", item.getRouteDescription()); // 生产令号
@ -1103,12 +1113,6 @@ public class ProcessOrderProController extends BaseController {
map.put("materialName", item.getMaterialName()); // 物料名称
map.put("material", item.getMaterial()); // 材质
map.put("discWeight", item.getDiscWeight()); // 单重KG
map.put("rawMaterialCode", item.getRawMaterialCode()); // 材料BOM物料编码
map.put("rawMaterialName", item.getRawMaterialName()); // 材料BOM物料名称
map.put("bomMaterial", item.getBomMaterial()); // BOM材质
map.put("bomDanZhong", item.getBomDanZhong()); // 材料单重KG
map.put("discUsage", item.getDiscUsage()); // 用量
map.put("bomUnit", item.getBomUnit()); // 单位
map.put("processNo", item.getProcessNo()); // 工序号
map.put("workCenter", item.getWorkCenter()); // 工作中心
map.put("processName", item.getProcessName()); // 工序名称
@ -1153,14 +1157,78 @@ public class ProcessOrderProController extends BaseController {
// 1. 读取第一个sheet的数据list - 使用POI直接读取以保留空格
List<ProductionOrderVo> allDataList = readExcelWithPOI(excelName);
List<ProcessRoute> routeList = readExcelPOIRoute(excelName);
//获取此项目的物料最新BOM 并且 将工艺路线拉取出来
ArrayList<ProcessRoute> routes = new ArrayList<>();
for (ProcessRoute processRoute : routeList) {
//TODO 获取最新的BOM版本的型号
String bomVersion = JdUtil.readGetTheLatestVersion(processRoute.getMaterialCode());
//TODO 获取此物料的所有工艺路线
List<ProcessRoute> routes = new ArrayList<>();
List<Map<String, Object>> kingdeeBomRows = new ArrayList<>();
for (ProcessRoute base : routeList) {
String materialCode = base.getMaterialCode();
if (StringUtils.isBlank(materialCode)) {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
routes.add(item);
continue;
}
String bomversion = JdUtil.readGetTheLatestVersion(materialCode);
List<MaterialUseDTO> bomItems = StringUtils.isNotBlank(bomversion) ? JdUtil.getMaterialUseXByVer(bomversion) : Collections.emptyList();
List<ProcessRouteDTO> routeGuDing = JdUtil.getRouteGuDing(materialCode);
if (bomItems != null && !bomItems.isEmpty()) {
for (MaterialUseDTO b : bomItems) {
Map<String, Object> bomMap = new HashMap<>();
bomMap.put("routeDescription", base.getRouteDescription());
bomMap.put("materialCode", base.getMaterialCode());
bomMap.put("materialName", base.getMaterialName());
bomMap.put("material", base.getMaterial());
bomMap.put("discWeight", base.getDiscWeight());
bomMap.put("rawMaterialCode", b.getMaterialCode());
bomMap.put("rawMaterialName", b.getMaterialName());
bomMap.put("bomMaterial", b.getCaizhi());
bomMap.put("bomDanZhong", b.getDanzhong());
bomMap.put("discUsage", (b.getFenzi() != null && b.getFenmu() != null) ? (b.getFenzi() + "/" + b.getFenmu()) : null);
bomMap.put("bomUnit", b.getChildUnit());
kingdeeBomRows.add(bomMap);
}
}
if (routeGuDing != null && !routeGuDing.isEmpty()) {
routeGuDing.stream()
.forEach(r -> {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
// 不写入BOM字段保持纯工艺数据行
item.setProcessNo(r.getProcessNo());
item.setWorkCenter(r.getWorkCenter());
item.setProcessName(r.getProcessName());
item.setProcessDescription(r.getProcessDescription());
item.setProcessControl(r.getProcessControl());
item.setActivityDuration(r.getActivityDuration());
item.setActivityUnit(r.getActivityUnit());
routes.add(item);
});
} else {
ProcessRoute item = new ProcessRoute();
item.setRouteDescription(base.getRouteDescription());
item.setMaterialCode(base.getMaterialCode());
item.setMaterialName(base.getMaterialName());
item.setMaterial(base.getMaterial());
item.setDiscWeight(base.getDiscWeight());
item.setUnitQuantity(base.getUnitQuantity());
item.setBatchQuantity(base.getBatchQuantity());
// 不写入BOM字段保持纯工艺数据行
routes.add(item);
}
}
// 用生成的 routes 替换原始 routeList保持原序展开后的结构用于后续导出
routeList = routes;
// 2. 读取原始表数据
List<BomDataVO> rawDataList = readRawDataTable(rawDataFile);
@ -1311,7 +1379,7 @@ public class ProcessOrderProController extends BaseController {
}
// 使用Excel模板文件
String templatePath = "D:/java/excel-template/生产及工艺计划模版.xlsx";
String templatePath = "jpg/生产及工艺计划模版.xlsx";
String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx";
// 准备模板数据
@ -1383,11 +1451,15 @@ public class ProcessOrderProController extends BaseController {
List<Map<String, Object>> evoDataList = convertEVOProductsDataToMapList(evoProductsList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("EVOProductsDataVO", evoDataList));
}
if (!kingdeeBomRows.isEmpty()) {
List<Map<String, Object>> bomDataList2 = convertKingdeeBomToMapList(kingdeeBomRows);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("KingdeeBomData", bomDataList2));
}
// 添加伊特产品数据
/*if (!excelDTOList.isEmpty()) {
List<Map<String, Object>> evoRouteDataList = convertRouteDataToMapList(excelDTOList);
if (!routeList.isEmpty()) {
List<Map<String, Object>> evoRouteDataList = convertRouteDataToMapList(routeList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessRouteExcelDTO", evoRouteDataList));
}*/
}
// 使用模板导出Excel
ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, outputPath, staticDataMap, dynamicDataMappingList);
@ -1421,16 +1493,28 @@ public class ProcessOrderProController extends BaseController {
}
}
private List<Map<String, Object>> convertKingdeeBomToMapList(List<Map<String, Object>> kingdeeBomRows) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (Map<String, Object> row : kingdeeBomRows) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
map.put("routeDescription", row.get("routeDescription"));
map.put("materialCode", row.get("materialCode"));
map.put("materialName", row.get("materialName"));
map.put("material", row.get("material"));
map.put("discWeight", row.get("discWeight"));
map.put("rawMaterialCode", row.get("rawMaterialCode"));
map.put("rawMaterialName", row.get("rawMaterialName"));
map.put("bomMaterial", row.get("bomMaterial"));
map.put("bomDanZhong", row.get("bomDanZhong"));
map.put("discUsage", row.get("discUsage"));
map.put("bomUnit", row.get("bomUnit"));
mapList.add(map);
index++;
}
return mapList;
}
}

View File

@ -1,5 +1,10 @@
package com.ruoyi.system.domain.dto;
public class JdVersionDTO {
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class JdVersionDTO {
@JsonProperty("FNumber")
private String version;
}

View File

@ -12,6 +12,7 @@ import com.kingdee.bos.webapi.entity.RepoRet;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.JdUtils;
import com.ruoyi.common.utils.VersionComparator;
import com.ruoyi.system.domain.BomDetails;
import com.ruoyi.system.domain.PartCost;
import com.ruoyi.system.domain.dto.*;
@ -2488,7 +2489,6 @@ public class JdUtil {
/**
* 获取物料清单
*
* @param FMaterialCode
* @return
*/
@ -3232,68 +3232,104 @@ public class JdUtil {
*/
public static String readGetTheLatestVersion(String materialCode) {
K3CloudApi client = new K3CloudApi();
// 请求参数要求为json字符串
JsonObject json = new JsonObject();
json.addProperty("FormId", "SFC_OperationReport");
json.addProperty("FieldKeys", "F_HBYT_SCLH,FBillNo,FMoNumber,FWorkShopID.FName,FOperNumber,FOperDescription,FQuaQty,FFinishQty,FStockInQuaAuxQty,FStockInFailAuxQty,F_HBYT_RKD,FDate");
// 是否为入库点
JsonObject filterObject = new JsonObject();
json.addProperty("FormId", "ENG_BOM");
json.addProperty("FieldKeys", "FNumber");
JsonArray filterString = new JsonArray();
filterObject.addProperty("FieldName", "F_HBYT_RKD");
filterObject.addProperty("Compare", "74");
filterObject.addProperty("Value", true);
JsonObject filterObject = new JsonObject();
filterObject.addProperty("FieldName", "FMATERIALID.FNumber");
filterObject.addProperty("Compare", "67");
filterObject.addProperty("Value", materialCode);
filterObject.addProperty("Left", "");
filterObject.addProperty("Right", "");
filterObject.addProperty("Logic", 0);
filterString.add(filterObject);
JsonObject filterObject1 = new JsonObject();
filterObject1.addProperty("FieldName", "FDocumentStatus");
filterObject1.addProperty("FieldName", "FForbidStatus");
filterObject1.addProperty("Compare", "105");
filterObject1.addProperty("Value", "A");
filterObject1.addProperty("Left", "");
filterObject1.addProperty("Right", "");
filterObject1.addProperty("Logic", 1);
filterObject1.addProperty("Logic", 0);
filterString.add(filterObject1);
JsonObject filterObject2 = new JsonObject();
filterObject2.addProperty("FieldName", "FDocumentStatus");
filterObject2.addProperty("Compare", "105");
filterObject2.addProperty("Value", "B");
filterObject2.addProperty("Left", "");
filterObject2.addProperty("Right", "");
filterObject2.addProperty("Logic", 1);
filterString.add(filterObject2);
json.add("FilterString", filterString);
json.addProperty("OrderString", "");
json.addProperty("TopRowCount", 0);
json.addProperty("StartRow", 0);
json.addProperty("Limit", 10000);
json.addProperty("Limit", 2000);
json.addProperty("SubSystemId", "");
List<ProcessReportDTO> processReportDTOList = new ArrayList<>();
int pageSize = 10000;
int startRow = 0;
List<JdVersionDTO> processReportDTOList = new ArrayList<>();
ObjectMapper objectMapper = new ObjectMapper();
try {
while (true) {
JsonObject pageJson = new Gson().fromJson(json.toString(), JsonObject.class);
pageJson.addProperty("StartRow", startRow);
pageJson.addProperty("Limit", pageSize);
String resultJson = String.valueOf(client.billQuery(pageJson.toString()));
JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class);
if (jsonArray == null || jsonArray.size() == 0) {
break;
}
List<ProcessReportDTO> pageList = objectMapper.readValue(jsonArray.toString(), new TypeReference<List<ProcessReportDTO>>() {
String resultJson = String.valueOf(client.billQuery(json.toString()));
JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class);
if (jsonArray != null && jsonArray.size() > 0) {
List<JdVersionDTO> pageList = objectMapper.readValue(jsonArray.toString(), new TypeReference<List<JdVersionDTO>>() {
});
processReportDTOList.addAll(pageList);
if (jsonArray.size() < pageSize) {
break;
}
startRow += pageSize;
}
} catch (Exception e) {
e.printStackTrace(); // 输出异常日志
e.printStackTrace();
}
if (processReportDTOList.isEmpty()) {
return null;
}
String latest = processReportDTOList.stream()
.map(JdVersionDTO::getVersion)
.filter(Objects::nonNull)
.max(new VersionComparator())
.orElse(null);
return latest;
}
/**
* 根据bom版本获取物料清单
* @param version
* @return
*/
public static List<MaterialUseDTO> getMaterialUseXByVer(String version) {
K3CloudApi client = new K3CloudApi();
// 请求参数要求为json字符串
JsonObject json = new JsonObject();
json.addProperty("FormId", "ENG_BOM");
json.addProperty("FieldKeys", "FNumber,FMATERIALIDCHILD.FNumber,FCHILDITEMNAME,FCHILDUNITID.FName,FNUMERATOR,FDENOMINATOR,F_HBYT_DZ,F_HBYT_CZ");
JsonArray filterString = new JsonArray();
JsonObject filterObject = new JsonObject();
filterObject.addProperty("FieldName", "FNumber");
filterObject.addProperty("Compare", "67");
filterObject.addProperty("Value", version);
filterObject.addProperty("Left", "");
filterObject.addProperty("Right", "");
filterObject.addProperty("Logic", 0);
filterString.add(filterObject);
JsonObject filterObject1 = new JsonObject();
filterObject1.addProperty("FieldName", "FForbidStatus");
filterObject1.addProperty("Compare", "105");
filterObject1.addProperty("Value", "A");
filterObject1.addProperty("Left", "");
filterObject1.addProperty("Right", "");
filterObject1.addProperty("Logic", 0);
filterString.add(filterObject1);
json.add("FilterString", filterString);
json.addProperty("OrderString", "");
json.addProperty("TopRowCount", 0);
json.addProperty("StartRow", 0);
json.addProperty("Limit", 2000);
json.addProperty("SubSystemId", "");
return " ";
String jsonData = json.toString();
try {
String resultJson = String.valueOf(client.billQuery(jsonData));
JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class);
if (jsonArray != null && jsonArray.size() > 0) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(jsonArray.toString(), new TypeReference<List<MaterialUseDTO>>() {
});
} else {
return Collections.emptyList();
}
} catch (Exception e) {
log.error("调用接口时发生异常: " + e.getMessage(), e);
}
return Collections.emptyList();
}
}

View File

@ -124,24 +124,18 @@ public class PartCostServiceImpl implements IPartCostService {
Map<String, PartCost> uniq = new LinkedHashMap<>();
for (PartCost pc : list) {
if (pc == null) continue;
String code = pc.getMaterialCode();
String name = pc.getMaterialName();
BigDecimal cost = pc.getCostPrice();
// 过滤无效数据
if (StringUtils.isBlank(code) || StringUtils.isBlank(name) || cost == null || cost.compareTo(BigDecimal.ZERO) == 0) {
continue;
}
// 物料编码 + 名称 为唯一键
String key = code + "|" + name;
PartCost existing = uniq.get(key);
// 保留 createDate 最新的
if (existing == null ||
(pc.getCreateDate() != null &&
(existing.getCreateDate() == null || pc.getCreateDate().after(existing.getCreateDate())))) {
if (existing == null || (pc.getCreateDate() != null && (existing.getCreateDate() == null || pc.getCreateDate().after(existing.getCreateDate())))) {
uniq.put(key, pc);
}
}