# Conflicts:
#	ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java
#	ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessRouteExcelDTO.java
#	ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java
#	ruoyi-system/src/main/resources/EXCEL模板/生产及工艺计划模版.xlsx
This commit is contained in:
tzy 2025-09-26 14:53:24 +08:00
commit 8294672ce6
28 changed files with 1044 additions and 456 deletions

View File

@ -7,10 +7,12 @@ import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
import java.io.*; import java.io.*;
import java.nio.file.Files;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -22,27 +24,29 @@ import java.util.Map;
public class ExcelTemplateProc { public class ExcelTemplateProc {
/** /**
* @param templateFileName * 根据模版导出Excel入口
* @param exportFilePathAndName * @param templateFileName 模板文件路径可以是classpath路径 本地绝对路径
* @param staticDataMap * @param exportFilePathAndName 导出文件完整路径
* @param dynamicDataMappingList * @param staticDataMap 静态数据
* @return void * @param dynamicDataMappingList 动态数据
* @description: 根据模版导出Excel入口
* @author susu
* @date 2024/2/20
*/ */
public static void doExportExcelByTemplateProc(String templateFileName, String exportFilePathAndName, public static void doExportExcelByTemplateProc(String templateFileName,
String exportFilePathAndName,
Map<String, Object> staticDataMap, Map<String, Object> staticDataMap,
List<DynamicDataMapping> dynamicDataMappingList) throws IOException { List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
/**
* 1. 从resources下加载模板并替换 InputStream inputStream;
* 使用 ResourceUtils 加载文件
*/ if (templateFileName.startsWith("/") || templateFileName.contains(":")) {
File file = ResourceUtils.getFile("classpath:"+templateFileName); // 绝对路径 (Windows: D:/... Linux: /opt/...)
InputStream inputStream = new FileInputStream(file); inputStream = Files.newInputStream(new File(templateFileName).toPath());
} else {
// classpath 路径
ClassPathResource resource = new ClassPathResource(templateFileName);
inputStream = resource.getInputStream();
}
Workbook workbook = dealAllSheetsByTemplate(inputStream, staticDataMap, dynamicDataMappingList); Workbook workbook = dealAllSheetsByTemplate(inputStream, staticDataMap, dynamicDataMappingList);
// 2. 保存到本地
saveExportFile(workbook, exportFilePathAndName); saveExportFile(workbook, exportFilePathAndName);
} }

View File

@ -0,0 +1,26 @@
package com.ruoyi.common.result;
import lombok.Data;
@Data
public class BOMUploadResult {
private boolean success; // 是否成功
private String id; // 金蝶内部ID
private String number; // 单据编号
private String errorMessage; // 错误信息失败时才有
public static BOMUploadResult success(String id, String number) {
BOMUploadResult result = new BOMUploadResult();
result.setSuccess(true);
result.setId(id);
result.setNumber(number);
return result;
}
public static BOMUploadResult fail(String errorMessage) {
BOMUploadResult result = new BOMUploadResult();
result.setSuccess(false);
result.setErrorMessage(errorMessage);
return result;
}
}

View File

@ -0,0 +1,179 @@
package com.ruoyi.common.utils;
import java.util.Comparator;
/**
* 版本号排序比较器
* 支持类似 30AD.1, 30AD.2, 30AD.01.1, 30AD.01.2, 30AD.01A.1, 30AD.01A.2 的排序
*
* 排序规则
* 1. 先按主要部分排序 30AD
* 2. 再按数字部分排序 1, 2, 01, 10
* 3. 最后按字母部分排序 A, B
*
* @author system
*/
public class VersionComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
if (s1 == null && s2 == null) {
return 0;
}
if (s1 == null) {
return -1;
}
if (s2 == null) {
return 1;
}
// 按点分割字符串
String[] parts1 = s1.split("\\.");
String[] parts2 = s2.split("\\.");
int maxLength = Math.max(parts1.length, parts2.length);
for (int i = 0; i < maxLength; i++) {
String part1 = i < parts1.length ? parts1[i] : "";
String part2 = i < parts2.length ? parts2[i] : "";
int result = comparePart(part1, part2);
if (result != 0) {
return result;
}
}
return 0;
}
/**
* 比较单个部分
* 支持数字和字母混合的比较
*/
private int comparePart(String part1, String part2) {
if (part1.equals(part2)) {
return 0;
}
// 如果其中一个为空空的小于非空的
if (part1.isEmpty()) {
return -1;
}
if (part2.isEmpty()) {
return 1;
}
// 特殊处理如果都是纯数字按数值比较
Integer num1 = parseNumber(part1);
Integer num2 = parseNumber(part2);
if (num1 != null && num2 != null) {
return num1.compareTo(num2);
}
// 分离数字和字母部分
String[] segments1 = splitNumberAndLetter(part1);
String[] segments2 = splitNumberAndLetter(part2);
// 比较每个段
int maxSegments = Math.max(segments1.length, segments2.length);
for (int i = 0; i < maxSegments; i++) {
String seg1 = i < segments1.length ? segments1[i] : "";
String seg2 = i < segments2.length ? segments2[i] : "";
int result = compareSegment(seg1, seg2);
if (result != 0) {
return result;
}
}
return 0;
}
/**
* 将字符串分离为数字和字母段
* 例如: "01A" -> ["01", "A"]
* "2" -> ["2"]
* "A" -> ["A"]
* "01FV" -> ["01", "FV"]
*/
private String[] splitNumberAndLetter(String str) {
if (str == null || str.isEmpty()) {
return new String[]{""};
}
StringBuilder result = new StringBuilder();
boolean lastWasDigit = false;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
boolean isDigit = Character.isDigit(c);
if (i > 0 && isDigit != lastWasDigit) {
result.append("|");
}
result.append(c);
lastWasDigit = isDigit;
}
return result.toString().split("\\|");
}
/**
* 比较单个段
*/
private int compareSegment(String seg1, String seg2) {
if (seg1.equals(seg2)) {
return 0;
}
if (seg1.isEmpty()) {
return -1;
}
if (seg2.isEmpty()) {
return 1;
}
// 尝试解析为数字
Integer num1 = parseNumber(seg1);
Integer num2 = parseNumber(seg2);
// 如果都是数字按数字比较
if (num1 != null && num2 != null) {
return num1.compareTo(num2);
}
// 如果一个是数字一个是字符串数字优先
if (num1 != null && num2 == null) {
return -1;
}
if (num1 == null && num2 != null) {
return 1;
}
// 如果都是字符串按字符串比较忽略大小写
return seg1.compareToIgnoreCase(seg2);
}
/**
* 尝试将字符串解析为数字
* 如果字符串只包含数字则返回对应的Integer
* 否则返回null
*/
private Integer parseNumber(String str) {
if (str == null || str.isEmpty()) {
return null;
}
try {
// 检查是否只包含数字
if (str.matches("\\d+")) {
return Integer.parseInt(str);
}
} catch (NumberFormatException e) {
// 忽略异常返回null
}
return null;
}
}

View File

@ -3,6 +3,9 @@ package com.ruoyi.system.controller;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONArray; import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
@ -18,16 +21,20 @@ import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.validate.AddGroup; import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup; import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.result.BOMUploadResult;
import com.ruoyi.common.utils.JdUtils; import com.ruoyi.common.utils.JdUtils;
import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.BomDetails; import com.ruoyi.system.domain.BomDetails;
import com.ruoyi.system.domain.FigureSave; import com.ruoyi.system.domain.FigureSave;
import com.ruoyi.system.domain.MaterialProperties; import com.ruoyi.system.domain.MaterialProperties;
import com.ruoyi.system.domain.ProcessOrderPro;
import com.ruoyi.system.domain.bo.BomDetailsBo; import com.ruoyi.system.domain.bo.BomDetailsBo;
import com.ruoyi.system.domain.bo.ProcessOrderProBo; import com.ruoyi.system.domain.bo.ProcessOrderProBo;
import com.ruoyi.system.domain.dto.JdValidateBomDTO; import com.ruoyi.system.domain.dto.JdValidateBomDTO;
import com.ruoyi.system.domain.dto.JdChildDTO; import com.ruoyi.system.domain.dto.JdChildDTO;
import com.ruoyi.system.domain.dto.KindegeeLogDTO;
import com.ruoyi.system.domain.vo.BomDetailsVo; import com.ruoyi.system.domain.vo.BomDetailsVo;
import com.ruoyi.system.domain.vo.ElectricalMaterialBomVO;
import com.ruoyi.system.mapper.FigureSaveMapper; import com.ruoyi.system.mapper.FigureSaveMapper;
import com.ruoyi.system.mapper.ProcessOrderProMapper; import com.ruoyi.system.mapper.ProcessOrderProMapper;
import com.ruoyi.system.runner.JdUtil; import com.ruoyi.system.runner.JdUtil;
@ -49,6 +56,7 @@ import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal;
import java.util.*; import java.util.*;
import static org.aspectj.bridge.MessageUtil.fail; import static org.aspectj.bridge.MessageUtil.fail;
@ -354,12 +362,13 @@ public class BomDetailsController extends BaseController {
@PostMapping("/updateFBMaterial") @PostMapping("/updateFBMaterial")
public R updateFBMaterial(@RequestBody List<Map<String, String>> bomDetailParams) { public R updateFBMaterial(@RequestBody List<Map<String, String>> bomDetailParams) {
List<BomDetails> bomDetailsList = new ArrayList<>(); List<BomDetails> bomDetailsList = new ArrayList<>();
Set<String> processedMaterials = new HashSet<>(); // 用于跟踪已处理的物料编码 List<KindegeeLogDTO> logDTOS = new ArrayList<>();
List<String> failedMaterials = new ArrayList<>(); // 用于跟踪处理失败的物料 List<String> failedMaterials = new ArrayList<>(); // 用于跟踪处理失败的物料
String totalWeight = ""; String totalWeight = "";
// 遍历前端传来的数据 // 遍历前端传来的数据
for (Map<String, String> param : bomDetailParams) { for (Map<String, String> param : bomDetailParams) {
String fnumber = param.get("fnumber"); // 物料编码 String fnumber = param.get("fnumber"); // 物料编码
String fname = param.get("fname"); // 物料编码
totalWeight = param.get("totalWeight"); // 生产令号 totalWeight = param.get("totalWeight"); // 生产令号
// 根据物料编码和生产令号查询 // 根据物料编码和生产令号查询
@ -367,15 +376,9 @@ public class BomDetailsController extends BaseController {
log.info("处理物料编码: {}, 生产令号: {}", fnumber, totalWeight); log.info("处理物料编码: {}, 生产令号: {}", fnumber, totalWeight);
if (bomDetails != null && !bomDetails.isEmpty()) { if (bomDetails != null && !bomDetails.isEmpty()) {
//TODO 处理父级物料 //TODO 处理父级物料
ProcessOrderProBo bo = iProcessOrderProService.selectByProjectNumber(totalWeight); ProcessOrderPro bo = iProcessOrderProService.selectByProjectNumber(totalWeight);
List<FigureSave> list = iFigureSaveService.selectByProCode(totalWeight); // 第一步处理所有物料的保存
if (list.size() > 0) {
for (FigureSave figureSave : list) {
String figureNumber = figureSave.getFigureNumber();
List<BomDetails> bomDetails1 = iBomDetailsService.selectByFNumberAndTotalWeight(figureNumber, totalWeight);
}
}
for (BomDetails material : bomDetails) { for (BomDetails material : bomDetails) {
// 获取工艺表中的非委外工时 // 获取工艺表中的非委外工时
Double fbWorkTime = iProcessRouteService.getFbWorkTime(material); Double fbWorkTime = iProcessRouteService.getFbWorkTime(material);
@ -383,7 +386,6 @@ public class BomDetailsController extends BaseController {
if (material.getPartNumber() != null && material.getName() != null && material.getUnitWeight().equals("")) { if (material.getPartNumber() != null && material.getName() != null && material.getUnitWeight().equals("")) {
String state = determineState(material); String state = determineState(material);
log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName()); log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
try { try {
int result = loadMaterialPreservation(material, state, fbWorkTime); int result = loadMaterialPreservation(material, state, fbWorkTime);
if (result == 1) { if (result == 1) {
@ -405,69 +407,179 @@ public class BomDetailsController extends BaseController {
} }
} }
// 保存物料清单之前进行BOM校验 // 第二步BOM校验和上传在循环外部
if (validateBOM(fnumber, bomDetails)) { boolean needUpload = !validateBOM(fnumber, bomDetails);
if (needUpload) {
try {
// 物料清单保存方法
BOMUploadResult bomUploadResult = FBloadBillOfMaterialsPreservation(bomDetails, bo);
if (bomUploadResult.isSuccess()) {
KindegeeLogDTO logDTO = new KindegeeLogDTO();
logDTO.setProjectCode(bo.getProductionOrderNo());
logDTO.setMaterialCode(fnumber); // 使用物料编码而不是单个物料的编码
logDTO.setMaterialName(fname);
logDTO.setCode(bomUploadResult.getNumber());
logDTO.setReason(bomUploadResult.getNumber()+"OK");
logDTOS.add(logDTO);
} else {
KindegeeLogDTO logDTO = new KindegeeLogDTO();
logDTO.setProjectCode(bo.getProductionOrderNo());
logDTO.setMaterialCode(fnumber);
logDTO.setMaterialName(fname);
logDTO.setCode(bomUploadResult.getNumber());
logDTO.setReason(bomUploadResult.getErrorMessage());
logDTOS.add(logDTO);
}
bomDetailsList.addAll(bomDetails);
} catch (Exception e) {
log.error("保存BOM失败, 物料编码: {}, 错误: {}", fnumber, e.getMessage());
failedMaterials.add(fnumber); failedMaterials.add(fnumber);
} }
} else {
// 物料清单保存方法 KindegeeLogDTO logDTO = new KindegeeLogDTO();
FBloadBillOfMaterialsPreservation(bomDetails, bo); logDTO.setProjectCode(bo.getProductionOrderNo());
bomDetailsList.addAll(bomDetails); logDTO.setMaterialCode(fnumber);
logDTO.setMaterialName(fname);
logDTO.setCode("200");
logDTO.setReason("BOM已存在且一致");
logDTOS.add(logDTO);
log.info("BOM已存在且一致物料编码: {},跳过保存", fnumber);
}
} }
} }
//更新项目进度 //更新项目进度
ProcessOrderProBo processOrderProBo = iProcessOrderProService.selectByProjectNumber(totalWeight); ProcessOrderPro processOrderProBo = iProcessOrderProService.selectByProjectNumber(totalWeight);
processOrderProBo.setDrawingType( JSONUtil.toJsonStr(logDTOS));
processOrderProBo.setBomStatus(2L); processOrderProBo.setBomStatus(2L);
processOrderProMapper.selectById(processOrderProBo); processOrderProMapper.updateById(processOrderProBo);
// 返回处理结果 // 返回处理结果
return R.ok("成功", bomDetailsList); return R.ok("成功", bomDetailsList);
} }
private boolean validateBOM(String fnumber, List<BomDetails> bomDetails) { private boolean validateBOM(String fnumber, List<BomDetails> bomDetails) {
List<JdValidateBomDTO> JDBomList = JdUtil.getSelectBomList(fnumber); List<JdValidateBomDTO> JDBomList = JdUtil.getSelectBomList(fnumber);
// 1. 判断BOM是否为空
if (JDBomList == null || JDBomList.isEmpty()) { if (JDBomList == null || JDBomList.isEmpty()) {
log.error("未在金蝶中找到相同的BOM,需要上传,物料编码: {}", fnumber); log.error("未在金蝶中找到相同的BOM需要上传,物料编码: {}", fnumber);
return false; // BOM为空,需要上传 return false;
} }
for (JdValidateBomDTO jdBom : JDBomList) { // 子项排序 PartNumber -> Name -> PartdiagramCode -> PartdiagramName 保证顺序唯一
// 3. 检查子项数量是否一致 bomDetails.sort(Comparator.comparing(BomDetails::getPartNumber, Comparator.nullsFirst(String::compareTo))
if (jdBom.getChilds().size() != bomDetails.size()) { .thenComparing(BomDetails::getName, Comparator.nullsFirst(String::compareTo))
continue; // 数量不一致,跳过这个BOM继续检查下一个 .thenComparing(BomDetails::getPartdiagramCode, Comparator.nullsFirst(String::compareTo))
.thenComparing(BomDetails::getPartdiagramName, Comparator.nullsFirst(String::compareTo)));
log.info("开始验证BOM - 物料编码: {}, 金蝶BOM数量: {}, 输入BOM子项数量: {}",
fnumber, JDBomList.size(), bomDetails.size());
for (int bomIndex = 0; bomIndex < JDBomList.size(); bomIndex++) {
JdValidateBomDTO jdBom = JDBomList.get(bomIndex);
List<JdChildDTO> childs = jdBom.getChilds();
log.debug("正在比较第{}个金蝶BOM - 子项数量: {}", bomIndex + 1, childs.size());
childs.sort(Comparator.comparing(JdChildDTO::getPartNumber, Comparator.nullsFirst(String::compareTo))
.thenComparing(JdChildDTO::getName, Comparator.nullsFirst(String::compareTo))
.thenComparing(JdChildDTO::getPartdiagramCode, Comparator.nullsFirst(String::compareTo))
.thenComparing(JdChildDTO::getPartdiagramName, Comparator.nullsFirst(String::compareTo)));
if (childs.size() != bomDetails.size()) {
log.warn("BOM子项数量不一致 - 物料编码: {}, 金蝶BOM子项数量: {}, 输入BOM子项数量: {}",
fnumber, childs.size(), bomDetails.size());
continue; // 数量不一致跳过当前金蝶BOM
} }
// 4. 比较每个子项的内容
boolean isMatch = true; boolean isMatch = true;
for (int i = 0; i < jdBom.getChilds().size(); i++) { List<String> mismatchDetails = new ArrayList<>();
JdChildDTO jdChild = jdBom.getChilds().get(i);
for (int i = 0; i < childs.size(); i++) {
JdChildDTO jdChild = childs.get(i);
BomDetails inputBomDetail = bomDetails.get(i); BomDetails inputBomDetail = bomDetails.get(i);
// 比较物料编码和名称 List<String> itemMismatches = new ArrayList<>();
if (!jdChild.getPartNumber().equals(inputBomDetail.getPartNumber()) || !jdChild.getName().equals(inputBomDetail.getName())) {
isMatch = false; // 字符串比较null/空格统一处理
break; if (!equalsStr(jdChild.getPartNumber(), inputBomDetail.getPartNumber())) {
itemMismatches.add(String.format("PartNumber [金蝶:'%s' vs 输入:'%s']",
jdChild.getPartNumber(), inputBomDetail.getPartNumber()));
} }
// 比较分子和分母 /* if (!equalsStr(jdChild.getName(), inputBomDetail.getName())) {
if (!jdChild.getDenominator().equals(inputBomDetail.getDenominator()) || !jdChild.getQuantity().equals(inputBomDetail.getQuantity())) { itemMismatches.add(String.format("Name [金蝶:'%s' vs 输入:'%s']",
jdChild.getName(), inputBomDetail.getName()));
}
*/
if (!equalsStr(jdChild.getPartdiagramCode(), inputBomDetail.getPartdiagramCode())) {
itemMismatches.add(String.format("PartdiagramCode [金蝶:'%s' vs 输入:'%s']",
jdChild.getPartdiagramCode(), inputBomDetail.getPartdiagramCode()));
}
/* if (!equalsStr(jdChild.getPartdiagramName(), inputBomDetail.getPartdiagramName())) {
itemMismatches.add(String.format("PartdiagramName [金蝶:'%s' vs 输入:'%s']",
jdChild.getPartdiagramName(), inputBomDetail.getPartdiagramName()));
}
*/
// 数值比较BigDecimal + stripTrailingZeros
BigDecimal jdQuantity = new BigDecimal(String.valueOf(jdChild.getQuantity())).stripTrailingZeros();
BigDecimal inputQuantity = new BigDecimal(String.valueOf(inputBomDetail.getQuantity())).stripTrailingZeros();
BigDecimal jdDenominator = new BigDecimal(String.valueOf(jdChild.getDenominator())).stripTrailingZeros();
BigDecimal inputDenominator = new BigDecimal(String.valueOf(inputBomDetail.getDenominator())).stripTrailingZeros();
if (jdQuantity.compareTo(inputQuantity) != 0) {
itemMismatches.add(String.format("Quantity [金蝶:%s vs 输入:%s]",
jdQuantity, inputQuantity));
}
if (jdDenominator.compareTo(inputDenominator) != 0) {
itemMismatches.add(String.format("Denominator [金蝶:%s vs 输入:%s]",
jdDenominator, inputDenominator));
}
// 如果有不匹配的字段记录详细信息
if (!itemMismatches.isEmpty()) {
String mismatchInfo = String.format("第%d项不匹配: %s", i + 1, String.join(", ", itemMismatches));
mismatchDetails.add(mismatchInfo);
isMatch = false; isMatch = false;
break; }
// 调试日志
log.debug("对比第{}项 -> PartNumber [{} vs {}], Name [{} vs {}], Code [{} vs {}], DiagramName [{} vs {}], Quantity [{} vs {}], Denominator [{} vs {}]",
i + 1,
jdChild.getPartNumber(), inputBomDetail.getPartNumber(),
jdChild.getName(), inputBomDetail.getName(),
jdChild.getPartdiagramCode(), inputBomDetail.getPartdiagramCode(),
jdChild.getPartdiagramName(), inputBomDetail.getPartdiagramName(),
jdQuantity, inputQuantity,
jdDenominator, inputDenominator);
}
// 如果不匹配打印详细的不一致信息
if (!isMatch) {
log.warn("BOM不匹配详情 - 物料编码: {}", fnumber);
log.warn("金蝶BOM子项数量: {}, 输入BOM子项数量: {}", childs.size(), bomDetails.size());
for (String mismatch : mismatchDetails) {
log.warn(" {}", mismatch);
} }
} }
if (isMatch) { if (isMatch) {
// 找到匹配的BOM无需上传
log.info("BOM完全相同物料编码: {},无需上传", fnumber); log.info("BOM完全相同物料编码: {},无需上传", fnumber);
return true; return true; // 找到匹配BOM
} }
} }
// 所有BOM都不匹配需要上传
log.info("BOM不存在或不一致物料编码: {},需要上传", fnumber); log.info("BOM不存在或不一致物料编码: {},需要上传", fnumber);
return false; return false; // 所有BOM都不匹配
}
// null/空格统一处理方法
private boolean equalsStr(String a, String b) {
String s1 = (a == null || a.trim().isEmpty()) ? "" : a.trim();
String s2 = (b == null || b.trim().isEmpty()) ? "" : b.trim();
return s1.equals(s2);
} }
@ -589,7 +701,7 @@ public class BomDetailsController extends BaseController {
} }
// FBOM物料清单保存 // FBOM物料清单保存
public void FBloadBillOfMaterialsPreservation(List<BomDetails> bomlist, ProcessOrderProBo bo) { public BOMUploadResult FBloadBillOfMaterialsPreservation(List<BomDetails> bomlist, ProcessOrderPro bo) {
BomDetails bomDetails1 = bomlist.get(0); BomDetails bomDetails1 = bomlist.get(0);
int verification = isMaterialVerification(bomDetails1.getFNumber(), bomDetails1.getFName()); int verification = isMaterialVerification(bomDetails1.getFNumber(), bomDetails1.getFName());
@ -648,7 +760,7 @@ public class BomDetailsController extends BaseController {
List<JsonObject> fTreeEntityList = new ArrayList<>(); List<JsonObject> fTreeEntityList = new ArrayList<>();
for (BomDetails details : bomlist) { for (BomDetails details : bomlist) {
if (bomlist.isEmpty()) { if (bomlist.isEmpty()) {
return; return null;
} }
// 创建FTreeEntity对象并加入FTreeEntity数组 // 创建FTreeEntity对象并加入FTreeEntity数组
JsonObject fTreeEntityItem = new JsonObject(); JsonObject fTreeEntityItem = new JsonObject();
@ -673,7 +785,6 @@ public class BomDetailsController extends BaseController {
} }
fTreeEntityItem.addProperty("FSupplyType", supplyType); fTreeEntityItem.addProperty("FSupplyType", supplyType);
} }
fTreeEntityItem.addProperty("FMATERIALTYPE", "1"); fTreeEntityItem.addProperty("FMATERIALTYPE", "1");
// 创建FMATERIALIDCHILD对象并加入FTreeEntity // 创建FMATERIALIDCHILD对象并加入FTreeEntity
JsonObject fMaterialIdChild = new JsonObject(); JsonObject fMaterialIdChild = new JsonObject();
@ -708,30 +819,23 @@ public class BomDetailsController extends BaseController {
fTreeEntityItem.add("FOWNERID", FOWNERID); fTreeEntityItem.add("FOWNERID", FOWNERID);
FOWNERID.addProperty("FNumber", "GYS_070"); FOWNERID.addProperty("FNumber", "GYS_070");
} }
fTreeEntityList.add(fTreeEntityItem); fTreeEntityList.add(fTreeEntityItem);
} }
String jsonData = json.toString(); String jsonData = json.toString();
log.info("打印json:" + jsonData);
try { try {
// 业务对象标识 String resultJson = new K3CloudApi().save("ENG_BOM", json.toString());
String formId = "ENG_BOM"; // 直接用 Jackson 解析
// 调用接口 BOMUploadResult result = parseK3Response(resultJson);
String resultJson = client.save(formId, jsonData); if (result.isSuccess()) {
log.info("✅ BOM保存成功, 图号={}", bomDetails1.getFNumber());
// 用于记录结果
Gson gson = new Gson();
// 对返回结果进行解析和校验
RepoRet repoRet = gson.fromJson(resultJson, RepoRet.class);
if (repoRet.getResult().getResponseStatus().isIsSuccess()) {
log.debug("物料清单bom 保存成功===================>" + "图号:" + bomDetails1.getFNumber());
} else { } else {
log.error("物料清单bom 保存失败===================>" + "图号:" + bomDetails1.getFNumber()); log.error("❌ BOM保存失败, 图号={}, 错误={}", bomDetails1.getFNumber(), result.getErrorMessage());
} }
return result;
} catch (Exception e) { } catch (Exception e) {
R.fail(e.getMessage()); log.error("保存BOM异常图号={}, 错误={}", bomDetails1.getFNumber(), e.getMessage(), e);
return BOMUploadResult.fail("保存BOM异常: " + e.getMessage());
} }
// 输出生成的Json
} }
/* /*
@ -2031,5 +2135,51 @@ public class BomDetailsController extends BaseController {
} }
return 1; return 1;
} }
public BOMUploadResult parseK3Response(String jsonResponse) {
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(jsonResponse);
JsonNode result = root.path("Result");
JsonNode responseStatus = result.path("ResponseStatus");
boolean isSuccess = responseStatus.path("IsSuccess").asBoolean(false);
if (isSuccess) {
String id = result.path("Id").asText();
String number = result.path("Number").asText();
return BOMUploadResult.success(id, number);
} else {
JsonNode errors = responseStatus.path("Errors");
String errorMsg = (errors != null && errors.isArray() && !errors.isEmpty())
? errors.toString()
: "未知错误";
return BOMUploadResult.fail(errorMsg);
}
} catch (Exception e) {
return BOMUploadResult.fail("解析返回信息失败: " + e.getMessage());
}
}
/**
* 导入BOM
* daorubaon
*
* @param file 导入文件
*/
@Log(title = "明细导入", businessType = BusinessType.IMPORT)
@SaCheckPermission("system:details:import")
@PostMapping(value = "/importData21", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<Void> importData21(@RequestPart("file") MultipartFile file) throws Exception {
List<ElectricalMaterialBomVO> electricalMaterialBomVOS = ExcelUtil.importExcel(file.getInputStream(), ElectricalMaterialBomVO.class);
for (ElectricalMaterialBomVO bomVO : electricalMaterialBomVOS) {
BomDetails bomDetails = new BomDetails();
bomDetails.setTotalWeight(bomVO.getProductionOrderNo());
bomDetails.setFNumber(bomVO.getDrawingNo());
bomDetails.setFName(bomVO.getDrawingName());
bomDetails.setPartdiagramCode(bomVO.getParentDrawingNo());
bomDetails.setPartdiagramName(bomVO.getParentPart());
}
return null;
}
} }

View File

@ -527,5 +527,17 @@ public class EleMaterialsController extends BaseController {
return R.ok("更新成功"); return R.ok("更新成功");
} }
@Log(title = "更新物料单重", businessType = BusinessType.IMPORT)
@SaCheckPermission("system:materials:importEleBom")
@PostMapping(value = "/importEleBom", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<Void> importEleBom(@RequestParam("file") MultipartFile file) throws Exception {
String originalFilename = file.getOriginalFilename();
log.info("读取文件名: " + originalFilename);
ExcelResult<JdDanZhong> result = ExcelUtil.importExcelSheet1(file.getInputStream(), JdDanZhong.class, true);
List<JdDanZhong> list = result.getList();
return R.ok("更新成功");
}
} }

View File

@ -284,14 +284,14 @@ public class ImMaterialController extends BaseController {
json.addProperty("FormId", "BD_MATERIAL"); json.addProperty("FormId", "BD_MATERIAL");
json.addProperty("FieldKeys", "FMATERIALID,FNumber,FName,FCategoryID.FNumber,F_HBYT_DZ,F_SVRI_Assistant.FNumber,FErpClsID,FBaseUnitId.FName,FModifyDate,FForbidStatus"); json.addProperty("FieldKeys", "FMATERIALID,FNumber,FName,FCategoryID.FNumber,F_HBYT_DZ,F_SVRI_Assistant.FNumber,FErpClsID,FBaseUnitId.FName,FModifyDate,FForbidStatus");
JsonArray filterString = new JsonArray(); JsonArray filterString = new JsonArray();
JsonObject filterObject = new JsonObject(); /*JsonObject filterObject = new JsonObject();
filterObject.addProperty("FieldName", "FForbidStatus"); // 使用传入的 fieldName filterObject.addProperty("FieldName", "FForbidStatus"); // 使用传入的 fieldName
filterObject.addProperty("Compare", "105"); filterObject.addProperty("Compare", "105");
filterObject.addProperty("Value", "A"); filterObject.addProperty("Value", "A");
filterObject.addProperty("Left", ""); filterObject.addProperty("Left", "");
filterObject.addProperty("Right", ""); filterObject.addProperty("Right", "");
filterObject.addProperty("Logic", 0); filterObject.addProperty("Logic", 0);
filterString.add(filterObject); filterString.add(filterObject);*/
JsonObject filterObject1 = new JsonObject(); JsonObject filterObject1 = new JsonObject();
filterObject1.addProperty("FieldName", "FCreateDate"); // 使用传入的 fieldName filterObject1.addProperty("FieldName", "FCreateDate"); // 使用传入的 fieldName
filterObject1.addProperty("Compare", "93"); filterObject1.addProperty("Compare", "93");
@ -301,7 +301,7 @@ public class ImMaterialController extends BaseController {
filterObject1.addProperty("Logic", 1); filterObject1.addProperty("Logic", 1);
filterString.add(filterObject1); filterString.add(filterObject1);
JsonObject filterObject2 = new JsonObject(); JsonObject filterObject2 = new JsonObject();
filterObject2.addProperty("FieldName", "FCreateDate"); // 使用传入的 fieldName filterObject2.addProperty("FieldName", "FModifyDate"); // 使用传入的 fieldName
filterObject2.addProperty("Compare", "93"); filterObject2.addProperty("Compare", "93");
filterObject2.addProperty("Value", date); filterObject2.addProperty("Value", date);
filterObject2.addProperty("Left", ""); filterObject2.addProperty("Left", "");
@ -356,7 +356,7 @@ public class ImMaterialController extends BaseController {
//请求参数要求为json字符串 //请求参数要求为json字符串
JsonObject json = new JsonObject(); JsonObject json = new JsonObject();
json.addProperty("FormId", "BD_MATERIAL"); json.addProperty("FormId", "BD_MATERIAL");
json.addProperty("FieldKeys", "FMATERIALID,FNumber,FName,FCategoryID.FNumber,F_HBYT_DZ,F_SVRI_Assistant.FNumber,FErpClsID,FBaseUnitId.FName,FModifyDate,FForbidStatus,FIsVmiBusiness"); json.addProperty("FieldKeys", "FMATERIALID,FNumber,FName,F_HBYT_PP,FCategoryID.FNumber,F_HBYT_DZ,F_SVRI_Assistant.FNumber,FErpClsID,FBaseUnitId.FName,FModifyDate,FForbidStatus,FIsVmiBusiness");
JsonArray filterString = new JsonArray(); JsonArray filterString = new JsonArray();
log.debug("构建查询条件..."); log.debug("构建查询条件...");
@ -407,6 +407,7 @@ public class ImMaterialController extends BaseController {
* 保存所有的物料编码 * 保存所有的物料编码
* @return List<ImMaterial> * @return List<ImMaterial>
*/ */
@XxlJob("insertJDMaterial")
@GetMapping("/insertJDMaterial") @GetMapping("/insertJDMaterial")
public List<ImMaterial> insertJDMaterial() throws Exception { public List<ImMaterial> insertJDMaterial() throws Exception {
List<ImMaterial> materialList = loadMaterial(); List<ImMaterial> materialList = loadMaterial();

View File

@ -476,7 +476,7 @@ public class KingdeeWorkCenterDataController extends BaseController {
// 转入 // 转入
long transInQty = item.getLong("FTransInQty"); long transInQty = item.getLong("FTransInQty");
//转出小于转入数量 //转出小于转入数量
if (transOutQty<transInQty){ if (transOutQty < transInQty) {
// 转换为实体对象 // 转换为实体对象
KingdeeWorkCenterDataBo data = new KingdeeWorkCenterDataBo(); KingdeeWorkCenterDataBo data = new KingdeeWorkCenterDataBo();
data.setWorkCenter(workCenter); data.setWorkCenter(workCenter);
@ -763,6 +763,7 @@ public class KingdeeWorkCenterDataController extends BaseController {
log.info("物料处理完成,最终物料总数: {}", allStocks.size()); log.info("物料处理完成,最终物料总数: {}", allStocks.size());
return allStocks; return allStocks;
} }
@Log(title = "金蝶安全库存数据", businessType = BusinessType.OTHER) @Log(title = "金蝶安全库存数据", businessType = BusinessType.OTHER)
@XxlJob("getKuCunTo40SB") @XxlJob("getKuCunTo40SB")
public R<Void> getKuCunTo40SB() { public R<Void> getKuCunTo40SB() {
@ -775,13 +776,13 @@ public class KingdeeWorkCenterDataController extends BaseController {
String materialCode = "40SB/L"; String materialCode = "40SB/L";
// 获取即时库存 // 获取即时库存
double inventoryQty = Optional.ofNullable(JdUtil.getKuCun(materialCode)) double inventoryQty = Optional.ofNullable(JdUtil.getKuCun(materialCode))
.map(list ->list.stream() .map(list -> list.stream()
.mapToDouble(JDInventoryDTO::getFBaseQty) .mapToDouble(JDInventoryDTO::getFBaseQty)
.sum()) .sum())
.orElse(0.0); .orElse(0.0);
// 查询子项物料的未领料量 // 查询子项物料的未领料量
double fNoPickedQty = Optional.ofNullable(JdUtil.getWeiLingliao(materialCode)) double fNoPickedQty = Optional.ofNullable(JdUtil.getWeiLingliao(materialCode))
.map(list ->list.stream() .map(list -> list.stream()
.mapToDouble(JDProductionDTO::getFNoPickedQty) .mapToDouble(JDProductionDTO::getFNoPickedQty)
.sum()) .sum())
.orElse(0.0); .orElse(0.0);
@ -818,7 +819,6 @@ public class KingdeeWorkCenterDataController extends BaseController {
.append("> **创建时间:** ").append(DateUtil.formatDateTime(new Date())).append("\n"); .append("> **创建时间:** ").append(DateUtil.formatDateTime(new Date())).append("\n");
String part = markdownMsg.toString(); String part = markdownMsg.toString();
wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId); wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId);
@ -1011,10 +1011,10 @@ public class KingdeeWorkCenterDataController extends BaseController {
for (PurchaseRequestExcelDTO allOrder : allOrders) { for (PurchaseRequestExcelDTO allOrder : allOrders) {
String productionOrderNo = allOrder.getFUCHNText(); String productionOrderNo = allOrder.getFUCHNText();
String deliveryDate = allOrder.getFArrivalDate(); String deliveryDate = allOrder.getFArrivalDate();
if (allOrder.getFCloseStatus().equals("A")){ if (allOrder.getFCloseStatus().equals("A")) {
allOrder.setFCloseStatus("未关闭"); allOrder.setFCloseStatus("未关闭");
} }
if (allOrder.getFDocumentStatus().equals("C")){ if (allOrder.getFDocumentStatus().equals("C")) {
allOrder.setFDocumentStatus("已审核"); allOrder.setFDocumentStatus("已审核");
} }
@ -1048,6 +1048,7 @@ public class KingdeeWorkCenterDataController extends BaseController {
log.info("过滤完成,剩余数量: {}", filteredOrders.size()); log.info("过滤完成,剩余数量: {}", filteredOrders.size());
return filteredOrders; return filteredOrders;
} }
@Log(title = "采购订单和采购申请单临期数据") @Log(title = "采购订单和采购申请单临期数据")
@XxlJob("getPurchaseOrder2") @XxlJob("getPurchaseOrder2")
@PostMapping("/getPurchaseOrder2") @PostMapping("/getPurchaseOrder2")

View File

@ -119,7 +119,7 @@ public class PcRigidChainController extends BaseController {
} }
@SaCheckPermission("system:pcRigidChain:importVariableData')") @SaCheckPermission("system:pcRigidChain:importVariableData")
@PostMapping("/importVariableData") @PostMapping("/importVariableData")
public R<List<PcRigidChain>> importVariableData(@RequestParam("file") MultipartFile file) throws Exception { public R<List<PcRigidChain>> importVariableData(@RequestParam("file") MultipartFile file) throws Exception {
if (file == null || file.isEmpty()) { if (file == null || file.isEmpty()) {
@ -131,8 +131,10 @@ public class PcRigidChainController extends BaseController {
if (originalFilename == null || originalFilename.isEmpty()) { if (originalFilename == null || originalFilename.isEmpty()) {
return R.fail("文件名不能为空"); return R.fail("文件名不能为空");
} }
String type = "";
log.info("开始处理文件: {}, 文件大小: {} bytes", originalFilename, fileBytes.length);
String type = "";
if (originalFilename.contains("30D")) { if (originalFilename.contains("30D")) {
type = "30D"; type = "30D";
} else if (originalFilename.contains("30S")) { } else if (originalFilename.contains("30S")) {
@ -153,28 +155,45 @@ public class PcRigidChainController extends BaseController {
type = "125R"; type = "125R";
} }
log.info("检测到文件类型: {}", type);
//每个产品都会有 ,,+ //每个产品都会有 ,,+
List<String> AxialDirection = Arrays.asList("R", "L", "L+R"); List<String> axialDirection = Arrays.asList("R", "L", "L+R");
ExcelReaderBuilder read = EasyExcel.read(new ByteArrayInputStream(fileBytes)); ExcelReaderBuilder read = EasyExcel.read(new ByteArrayInputStream(fileBytes));
List<PcRigidChain> pcRigidChainsToUpdate = null; List<PcRigidChain> pcRigidChainsToUpdate = new ArrayList<>();
for (ReadSheet readSheet : read.build().excelExecutor().sheetList()) {
List<ReadSheet> sheetList = read.build().excelExecutor().sheetList();
log.info("Excel文件包含 {} 个工作表", sheetList.size());
for (ReadSheet readSheet : sheetList) {
log.info("正在处理工作表: {} (第{}页)", readSheet.getSheetName(), readSheet.getSheetNo() + 1);
DefaultExcelListener<PcRigidChainVo> excelListener = new DefaultExcelListener<>(true); DefaultExcelListener<PcRigidChainVo> excelListener = new DefaultExcelListener<>(true);
EasyExcel.read(new ByteArrayInputStream(fileBytes), PcRigidChainVo.class, excelListener) EasyExcel.read(new ByteArrayInputStream(fileBytes), PcRigidChainVo.class, excelListener)
.excelType(ExcelTypeEnum.XLS) .excelType(ExcelTypeEnum.XLS)
.sheet(readSheet.getSheetNo()) .sheet(readSheet.getSheetNo())
.headRowNumber(3) .headRowNumber(4)
.doRead(); .doRead();
List<PcRigidChainVo> list = excelListener.getExcelResult().getList(); List<PcRigidChainVo> list = excelListener.getExcelResult().getList();
pcRigidChainsToUpdate = new ArrayList<>(); log.info("工作表 {} 解析完成,共读取 {} 行数据", readSheet.getSheetName(), list.size());
// 批量查询数据库中的记录 // 批量查询数据库中的记录
log.debug("开始查询数据库中类型为 {} 的记录", type);
List<PcRigidChain> chains = iPcRigidChainService.selectPcRigidChainByType(type); List<PcRigidChain> chains = iPcRigidChainService.selectPcRigidChainByType(type);
log.info("数据库中共找到 {} 条类型为 {} 的记录", chains.size(), type);
Map<String, PcRigidChain> chainMap = chains.stream() Map<String, PcRigidChain> chainMap = chains.stream()
.collect(Collectors.toMap(c -> c.getTypeName() + "_" + c.getAxialDirection(), c -> c)); .collect(Collectors.toMap(c -> c.getTypeName() + "_" + c.getAxialDirection(), c -> c));
log.debug("数据库记录映射表构建完成,共 {} 个键值对", chainMap.size());
for (String s : AxialDirection) { int processedCount = 0;
int matchedCount = 0;
for (String s : axialDirection) {
log.debug("开始处理轴向方向: {}", s);
for (PcRigidChainVo pcRigidChainVO : list) { for (PcRigidChainVo pcRigidChainVO : list) {
processedCount++;
Long vOne = pcRigidChainVO.getVOne(); Long vOne = pcRigidChainVO.getVOne();
String sheetName = readSheet.getSheetName(); String sheetName = readSheet.getSheetName();
String box = ""; String box = "";
@ -187,40 +206,139 @@ public class PcRigidChainController extends BaseController {
} }
String typeName = type + "/" + s + "-" + vOne + "/" + box; String typeName = type + "/" + s + "-" + vOne + "/" + box;
String searchKey = typeName + "_" + s;
log.debug("此物料的完整图号:=====================>{}", typeName); log.debug("处理记录 {}: 完整图号={}, 搜索键={}", processedCount, typeName, searchKey);
// 从缓存中查找 // 从缓存中查找
PcRigidChain dbChain = chainMap.get(typeName + "_" + s); PcRigidChain dbChain = chainMap.get(searchKey);
if (dbChain != null) { if (dbChain != null) {
matchedCount++;
log.info("找到匹配记录: {}", typeName);
// 记录修改前的关键字段值
log.info("修改前字段值:");
log.info(" - ID: {}", dbChain.getId());
log.info(" - Journey: {} -> {}", dbChain.getJourney(), vOne);
log.info(" - TypeName: {} -> {}", dbChain.getTypeName(), typeName);
log.info(" - Type: {} -> {}", dbChain.getType(), type);
log.info(" - Box: {} -> {}", dbChain.getBox(), box);
log.info(" - AxialDirection: {} -> {}", dbChain.getAxialDirection(), s);
// 记录Excel中的关键字段值
log.info("Excel数据关键字段:");
log.info(" - VOne: {}", pcRigidChainVO.getVOne());
log.info(" - VTwo: {}", pcRigidChainVO.getVTwo());
log.info(" - VThree: {}", pcRigidChainVO.getVThree());
log.info(" - LOne: {}", pcRigidChainVO.getLOne());
log.info(" - LTwo: {}", pcRigidChainVO.getLTwo());
log.info(" - LThree: {}", pcRigidChainVO.getLThree());
log.info(" - SumWeight: {}", pcRigidChainVO.getSumWeight());
log.info(" - ChainWeight: {}", pcRigidChainVO.getChainWeight());
log.info(" - DynamicLoad: {}", pcRigidChainVO.getDynamicLoad());
log.info(" - DeadLoad: {}", pcRigidChainVO.getDeadLoad());
log.info(" - Speed: {}", pcRigidChainVO.getSpeed());
log.info(" - Efficiency: {}", pcRigidChainVO.getEfficiency());
log.info(" - ChainPitch: {}", pcRigidChainVO.getChainPitch());
log.info(" - PitchRadius: {}", pcRigidChainVO.getPitchRadius());
log.info(" - MinimumAltitude: {}", pcRigidChainVO.getMinimumAltitude());
log.info(" - SingleMeterChainWeight: {}", pcRigidChainVO.getSingleMeterChainWeight());
log.info(" - DrivingBoxWeight: {}", pcRigidChainVO.getDrivingBoxWeight());
log.info(" - ChainBoxWeight: {}", pcRigidChainVO.getChainBoxWeight());
log.info(" - Univalence: {}", pcRigidChainVO.getUnivalence());
// 执行字段复制和更新
BeanUtil.copyProperties(pcRigidChainVO, dbChain, "id"); BeanUtil.copyProperties(pcRigidChainVO, dbChain, "id");
dbChain.setJourney(vOne); dbChain.setJourney(vOne);
dbChain.setTypeName(typeName); dbChain.setTypeName(typeName);
dbChain.setType(type); dbChain.setType(type);
dbChain.setBox(box); dbChain.setBox(box);
dbChain.setAxialDirection(s); dbChain.setAxialDirection(s);
// dbChain.setUpdateBy(SecurityUtils.getUsername());
dbChain.setCreateTime(new Date()); dbChain.setCreateTime(new Date());
dbChain.setUpdateTime(new Date());
// 记录修改后的关键字段值
log.info("修改后字段值:");
log.info(" - Journey: {}", dbChain.getJourney());
log.info(" - TypeName: {}", dbChain.getTypeName());
log.info(" - Type: {}", dbChain.getType());
log.info(" - Box: {}", dbChain.getBox());
log.info(" - AxialDirection: {}", dbChain.getAxialDirection());
log.info(" - LOne: {}", dbChain.getLOne());
log.info(" - LTwo: {}", dbChain.getLTwo());
log.info(" - LThree: {}", dbChain.getLThree());
log.info(" - SumWeight: {}", dbChain.getSumWeight());
log.info(" - ChainWeight: {}", dbChain.getChainWeight());
log.info(" - DynamicLoad: {}", dbChain.getDynamicLoad());
log.info(" - DeadLoad: {}", dbChain.getDeadLoad());
log.info(" - Speed: {}", dbChain.getSpeed());
log.info(" - Efficiency: {}", dbChain.getEfficiency());
log.info(" - ChainPitch: {}", dbChain.getChainPitch());
log.info(" - PitchRadius: {}", dbChain.getPitchRadius());
log.info(" - MinimumAltitude: {}", dbChain.getMinimumAltitude());
log.info(" - SingleMeterChainWeight: {}", dbChain.getSingleMeterChainWeight());
log.info(" - DrivingBoxWeight: {}", dbChain.getDrivingBoxWeight());
log.info(" - ChainBoxWeight: {}", dbChain.getChainBoxWeight());
log.info(" - Univalence: {}", dbChain.getUnivalence());
log.info(" - CreateTime: {}", dbChain.getCreateTime());
log.info(" - UpdateTime: {}", dbChain.getUpdateTime());
pcRigidChainsToUpdate.add(dbChain); pcRigidChainsToUpdate.add(dbChain);
log.info("物料: {} 已添加到更新列表", typeName);
} else {
log.warn("未找到对应的数据库记录: {}", searchKey);
} }
} }
} }
log.info("工作表 {} 处理完成 - 处理记录数: {}, 匹配成功数: {}",
readSheet.getSheetName(), processedCount, matchedCount);
}
if (!pcRigidChainsToUpdate.isEmpty()) { if (!pcRigidChainsToUpdate.isEmpty()) {
log.info("开始批量更新数据库,共 {} 条记录", pcRigidChainsToUpdate.size());
int successCount = 0;
int failCount = 0;
for (PcRigidChain pcRigidChain : pcRigidChainsToUpdate) { for (PcRigidChain pcRigidChain : pcRigidChainsToUpdate) {
log.info("正在更新物料: {}, ID: {}", pcRigidChain.getTypeName(), pcRigidChain.getId());
// 记录更新前的关键字段值
log.info("更新前数据库字段值:");
log.info(" - Journey: {}", pcRigidChain.getJourney());
log.info(" - LOne: {}", pcRigidChain.getLOne());
log.info(" - LTwo: {}", pcRigidChain.getLTwo());
log.info(" - LThree: {}", pcRigidChain.getLThree());
log.info(" - SumWeight: {}", pcRigidChain.getSumWeight());
log.info(" - ChainWeight: {}", pcRigidChain.getChainWeight());
log.info(" - DynamicLoad: {}", pcRigidChain.getDynamicLoad());
log.info(" - DeadLoad: {}", pcRigidChain.getDeadLoad());
log.info(" - Speed: {}", pcRigidChain.getSpeed());
log.info(" - Efficiency: {}", pcRigidChain.getEfficiency());
log.info(" - ChainPitch: {}", pcRigidChain.getChainPitch());
log.info(" - PitchRadius: {}", pcRigidChain.getPitchRadius());
log.info(" - MinimumAltitude: {}", pcRigidChain.getMinimumAltitude());
log.info(" - SingleMeterChainWeight: {}", pcRigidChain.getSingleMeterChainWeight());
log.info(" - DrivingBoxWeight: {}", pcRigidChain.getDrivingBoxWeight());
log.info(" - ChainBoxWeight: {}", pcRigidChain.getChainBoxWeight());
log.info(" - Univalence: {}", pcRigidChain.getUnivalence());
int i = pcRigidChainMapper.updateById(pcRigidChain); int i = pcRigidChainMapper.updateById(pcRigidChain);
if (i > 0) { if (i > 0) {
log.debug("物料:{}更新成功!!", pcRigidChain.getTypeName()); successCount++;
log.info("物料:{} 更新成功!影响行数: {}", pcRigidChain.getTypeName(), i);
} else { } else {
log.debug("物料:{}更新失败!!", pcRigidChain.getTypeName()); failCount++;
} log.warn("物料:{} 更新失败!影响行数: {}", pcRigidChain.getTypeName(), i);
}
} else {
return R.fail("没有找到要更新的数据");
} }
} }
log.info("批量更新完成 - 成功: {} 条, 失败: {} 条", successCount, failCount);
} else {
log.warn("没有找到要更新的数据");
return R.fail("没有找到要更新的数据");
}
log.info("Excel导入处理完成共处理 {} 条记录", pcRigidChainsToUpdate.size());
return R.ok("导入成功", pcRigidChainsToUpdate); return R.ok("导入成功", pcRigidChainsToUpdate);
} }
} }

View File

@ -10,6 +10,7 @@ import com.alibaba.excel.EasyExcel;
import com.ruoyi.common.excel.DefaultExcelListener; import com.ruoyi.common.excel.DefaultExcelListener;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.VersionComparator;
import com.ruoyi.common.utils.file.SmbUtil; import com.ruoyi.common.utils.file.SmbUtil;
import com.ruoyi.common.poi.ExcelTemplateProc; import com.ruoyi.common.poi.ExcelTemplateProc;
import com.ruoyi.common.poi.DynamicDataMapping; import com.ruoyi.common.poi.DynamicDataMapping;
@ -61,16 +62,13 @@ import org.springframework.web.multipart.MultipartFile;
@Slf4j @Slf4j
@RequestMapping("/system/orderPro") @RequestMapping("/system/orderPro")
public class ProcessOrderProController extends BaseController { public class ProcessOrderProController extends BaseController {
private final IProcessOrderProService iProcessOrderProService; private final IProcessOrderProService iProcessOrderProService;
@Autowired @Autowired
private final ProductionOrderServiceImpl productionOrderService;
private final IMrpResultCheckService iMrpResultCheckService; private final IMrpResultCheckService iMrpResultCheckService;
private final IBomDetailsService iBomDetailsService;
private final ProcessOrderProMapper processOrderProMapper; private final ProcessOrderProMapper processOrderProMapper;
private final IImMaterialService imMaterialService; private final IImMaterialService imMaterialService;
private final ISafetyStockService iSafetyStockService; private final ISafetyStockService iSafetyStockService;
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy年MM月dd日");
/** /**
* 查询项目令号列表 * 查询项目令号列表
*/ */
@ -345,7 +343,8 @@ public class ProcessOrderProController extends BaseController {
public List<OverdueProjectVo> getOverdueProjects() { public List<OverdueProjectVo> getOverdueProjects() {
return iProcessOrderProService.getOverdueProjects(); return iProcessOrderProService.getOverdueProjects();
} }
@SaCheckPermission("system:orderPro:geMRPResults")
@Log(title = "获取MRP复核结果", businessType = BusinessType.OTHER)
@PostMapping("/getMRPResults/{id}") @PostMapping("/getMRPResults/{id}")
public R<List<MrpResultCheck>> geMRPResults(@PathVariable Long id) { public R<List<MrpResultCheck>> geMRPResults(@PathVariable Long id) {
return iMrpResultCheckService.getMRPResults(id); return iMrpResultCheckService.getMRPResults(id);
@ -372,7 +371,7 @@ public class ProcessOrderProController extends BaseController {
// 1. 读取第一个sheet的数据list - 使用POI直接读取以保留空格 // 1. 读取第一个sheet的数据list - 使用POI直接读取以保留空格
List<ProductionOrderVo> allDataList = readExcelWithPOI(excelName); List<ProductionOrderVo> allDataList = readExcelWithPOI(excelName);
List<ProcessRoute> routeList = readExcelPOIRoute(excelName);
// 2. 读取原始表数据 // 2. 读取原始表数据
List<BomDataVO> rawDataList = readRawDataTable(rawDataFile); List<BomDataVO> rawDataList = readRawDataTable(rawDataFile);
@ -392,7 +391,7 @@ public class ProcessOrderProController extends BaseController {
if (materialCode != null) { if (materialCode != null) {
String drawingNo = item.getDrawingNo(); String drawingNo = item.getDrawingNo();
String drawingName = item.getDrawingName(); String drawingName = item.getDrawingName();
if (drawingNo != null && drawingName != null) { if (drawingName != null) {
ImMaterial material = imMaterialService.selectByCodeAndName(drawingNo, drawingName); ImMaterial material = imMaterialService.selectByCodeAndName(drawingNo, drawingName);
if (material != null) { if (material != null) {
//判断是否是VMI物料 //判断是否是VMI物料
@ -407,7 +406,7 @@ public class ProcessOrderProController extends BaseController {
existingVmi.setQuantity(currentQuantity + itemQuantity); existingVmi.setQuantity(currentQuantity + itemQuantity);
Integer currentBatchQuantity = existingVmi.getBatchQuantity() != null ? existingVmi.getBatchQuantity() : 0; Integer currentBatchQuantity = existingVmi.getBatchQuantity() != null ? existingVmi.getBatchQuantity() : 0;
Integer itemBatchQuantity = item.getBatchQuantity() != null ? Integer.valueOf(item.getBatchQuantity()) : 0; Integer itemBatchQuantity = item.getBatchQuantity() != null ? Integer.parseInt(item.getBatchQuantity()) : 0;
existingVmi.setBatchQuantity(currentBatchQuantity + itemBatchQuantity); existingVmi.setBatchQuantity(currentBatchQuantity + itemBatchQuantity);
found = true; found = true;
break; break;
@ -432,15 +431,44 @@ public class ProcessOrderProController extends BaseController {
|| materialCode.startsWith("009001") || materialCode.startsWith("009081") || materialCode.startsWith("009001") || materialCode.startsWith("009081")
|| (remark != null && remark.contains("外购"))) { || (remark != null && remark.contains("外购"))) {
// 过滤安全库存如果属于安全库存则进入工艺数据列表 // 过滤安全库存如果属于安全库存则进入工艺数据列表
Boolean isSafeStock = iSafetyStockService.isSafeCode(materialCode); Boolean isSafeStock = iSafetyStockService.isSafeCode(materialCode.trim());
if (isSafeStock) { if (isSafeStock) {
// 属于安全库存添加到工艺数据列表 // 属于安全库存添加到工艺数据列表
processDataList.add(item); processDataList.add(item);
continue; // 已分类跳过后续检查 continue; // 已分类跳过后续检查
} else { } else {
// 不属于安全库存添加到电气外包列表 // 不属于安全库存检查是否已存在相同的DrawingNo
boolean found = false;
for (ElecOutDataVO existingElec : elecOutList) {
if (item.getDrawingNo() != null && item.getDrawingNo().equals(existingElec.getDrawingNo())) {
// 将数量和批次数量相加
Double currentQuantity = existingElec.getQuantity() != null ? existingElec.getQuantity() : 0.0;
Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0;
Double newQuantity = currentQuantity + itemQuantity;
existingElec.setQuantity(newQuantity);
// 批次数量相加String类型
String currentBatchQuantity = existingElec.getBatchQuantity() != null ? (existingElec.getBatchQuantity()).toString() : "0";
String itemBatchQuantity = item.getBatchQuantity() != null ? item.getBatchQuantity() : "0";
try {
Integer currentBatch = Integer.valueOf(currentBatchQuantity);
Integer itemBatch = Integer.valueOf(itemBatchQuantity);
String newBatchQuantity = String.valueOf(currentBatch + itemBatch);
existingElec.setBatchQuantity(Integer.valueOf(newBatchQuantity));
} catch (NumberFormatException e) {
// 如果转换失败保持原值
existingElec.setBatchQuantity(Integer.valueOf(currentBatchQuantity));
}
found = true;
break;
}
}
// 如果没有找到相同的DrawingNo则添加新的电气外包数据
if (!found) {
ElecOutDataVO elecData = convertToElecOutDataVO(item); ElecOutDataVO elecData = convertToElecOutDataVO(item);
elecOutList.add(elecData); elecOutList.add(elecData);
}
continue; // 已分类跳过后续检查 continue; // 已分类跳过后续检查
} }
} }
@ -464,7 +492,7 @@ public class ProcessOrderProController extends BaseController {
// 检查是否已存在相同的DrawingNo // 检查是否已存在相同的DrawingNo
boolean found = false; boolean found = false;
for (ProductionOrderVo existingProcess : processDataList) { for (ProductionOrderVo existingProcess : processDataList) {
if (materialCode != null && materialCode.equals(existingProcess.getDrawingNo())) { if (item.getDrawingNo() != null && item.getDrawingNo().equals(existingProcess.getDrawingNo())) {
// 将数量和批次数量相加 // 将数量和批次数量相加
Double currentQuantity = existingProcess.getQuantity() != null ? existingProcess.getQuantity() : 0.0; Double currentQuantity = existingProcess.getQuantity() != null ? existingProcess.getQuantity() : 0.0;
Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0; Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0;
@ -495,9 +523,9 @@ public class ProcessOrderProController extends BaseController {
} }
List<ProcessRouteExcelDTO> excelDTOList = iProcessOrderProService.getRouteAndBomDetail(processDataList,orderPro);
// 使用Excel模板文件 // 使用Excel模板文件
String templatePath = "EXCEL模板/生产及工艺计划模版.xlsx"; String templatePath = "D:/java/excel-template/生产及工艺计划模版.xlsx";
String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx"; String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx";
// 准备模板数据 // 准备模板数据
@ -505,9 +533,29 @@ public class ProcessOrderProController extends BaseController {
staticDataMap.put("productionOrderNo", orderPro.getProductionOrderNo()); staticDataMap.put("productionOrderNo", orderPro.getProductionOrderNo());
staticDataMap.put("productionName", orderPro.getProductionName()); staticDataMap.put("productionName", orderPro.getProductionName());
// 添加静态数据调试信息 //获取工艺数据信息
log.info("静态数据: {}", staticDataMap); List<ProcessRouteExcelDTO> excelDTOList = iProcessOrderProService.getRouteAndBomDetail(routeList,processDataList,orderPro);
excelDTOList.sort(Comparator.comparing(
ProcessRouteExcelDTO::getMaterial,
Comparator.nullsLast((m1, m2) -> {
// 总装部件优先
boolean isTotal1 = "总装部件".equals(m1);
boolean isTotal2 = "总装部件".equals(m2);
if (isTotal1 && !isTotal2) return -1;
if (!isTotal1 && isTotal2) return 1;
if (isTotal1 && isTotal2) return 0;
// 其他材质按字母顺序排序
if (m1 == null && m2 == null) return 0;
if (m1 == null) return 1;
if (m2 == null) return -1;
return m1.compareTo(m2);
})
).thenComparing(
ProcessRouteExcelDTO::getMaterialCode,
Comparator.nullsLast(new VersionComparator())
));
// 准备动态数据映射 // 准备动态数据映射
List<DynamicDataMapping> dynamicDataMappingList = new ArrayList<>(); List<DynamicDataMapping> dynamicDataMappingList = new ArrayList<>();
@ -552,10 +600,10 @@ public class ProcessOrderProController extends BaseController {
List<Map<String, Object>> evoDataList = convertEVOProductsDataToMapList(evoProductsList); List<Map<String, Object>> evoDataList = convertEVOProductsDataToMapList(evoProductsList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("EVOProductsDataVO", evoDataList)); dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("EVOProductsDataVO", evoDataList));
} }
// 添加工艺路线 // 添加伊特产品数据
if (!excelDTOList.isEmpty()) { if (!excelDTOList.isEmpty()) {
List<Map<String, Object>> routeExcelList = convertEVORoutesDataToMapList(excelDTOList); List<Map<String, Object>> evoRouteDataList = convertRouteDataToMapList(excelDTOList);
dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessRouteExcelDTO", routeExcelList)); dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessRouteExcelDTO", evoRouteDataList));
} }
// 使用模板导出Excel // 使用模板导出Excel
@ -590,6 +638,43 @@ public class ProcessOrderProController extends BaseController {
} }
} }
private List<ProcessRoute> readExcelPOIRoute(String excelName) {
List<ProcessRoute> resultList = new ArrayList<>();
try (FileInputStream fis = new FileInputStream(excelName);
XSSFWorkbook workbook = new XSSFWorkbook(fis)) {
XSSFSheet sheet = workbook.getSheetAt(6); // 读取第一个sheet
// 从第3行开始读取headRowNumber=2所以从第3行开始
for (int rowIndex = 2; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
XSSFRow row = sheet.getRow(rowIndex);
if (row == null) {
continue;
}
ProcessRoute vo = new ProcessRoute();
// 根据列索引读取数据保留原始空格
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.setBatchQuantity(getCellValueAsLong(row.getCell(18))); // 批次数量
vo.setUnitQuantity(getCellValueAsDouble(row.getCell(17))); // 批次数量
resultList.add(vo);
}
log.info("使用POI读取Excel成功共{}条记录", resultList.size());
} catch (Exception e) {
log.error("使用POI读取Excel失败", e);
throw new ServiceException("读取Excel文件失败: " + e.getMessage());
}
return resultList;
}
/** /**
* 读取RawDataTable数据 * 读取RawDataTable数据
@ -857,7 +942,7 @@ public class ProcessOrderProController extends BaseController {
elecData.setIndex(null); // ProductionOrder没有index字段 elecData.setIndex(null); // ProductionOrder没有index字段
elecData.setDrawingNo(item.getDrawingNo()); elecData.setDrawingNo(item.getDrawingNo());
elecData.setName(item.getDrawingName()); elecData.setName(item.getDrawingName());
elecData.setQuantity(item.getQuantity() != null ? item.getQuantity().intValue() : null); elecData.setQuantity(Double.valueOf(item.getQuantity() != null ? item.getQuantity().intValue() : null));
elecData.setMaterial(item.getMaterial()); elecData.setMaterial(item.getMaterial());
elecData.setUnitWeight(item.getSingleWeight() != null ? BigDecimal.valueOf(item.getSingleWeight()) : null); elecData.setUnitWeight(item.getSingleWeight() != null ? BigDecimal.valueOf(item.getSingleWeight()) : null);
elecData.setTotalWeight(item.getTotalWeight() != null ? BigDecimal.valueOf(item.getTotalWeight()) : null); elecData.setTotalWeight(item.getTotalWeight() != null ? BigDecimal.valueOf(item.getTotalWeight()) : null);
@ -991,73 +1076,16 @@ public class ProcessOrderProController extends BaseController {
} }
return mapList; return mapList;
} }
/**
* 转换ProcessRouteExcelDTO为Map列表用于模板
*/
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
private String formatDate(Date date) { private String formatDate(Date date) {
return date == null ? "" : DATE_FORMAT.format(date); return date == null ? "" : DATE_FORMAT.format(date);
} }
private List<Map<String, Object>> convertEVORoutesDataToMapList(List<ProcessRouteExcelDTO> evoProductsList) {
List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1;
for (ProcessRouteExcelDTO dto : evoProductsList) {
Map<String, Object> map = new HashMap<>();
map.put("index", index);
// 基础信息
map.put("routeDescription", dto.getRouteDescription());
map.put("materialCode", dto.getMaterialCode());
map.put("materialName", dto.getMaterialName());
map.put("material", dto.getMaterial());
map.put("discWeight", dto.getDiscWeight());
// BOM 部分
map.put("rawMaterialCode", dto.getRawMaterialCode());
map.put("rawMaterialName", dto.getRawMaterialName());
map.put("bomMaterial", dto.getBomMaterial());
map.put("bomDanZhong", dto.getBomDanZhong());
map.put("discUsage", dto.getDiscUsage());
map.put("bomUnit", dto.getBomUnit());
// 工艺部分
map.put("processNo", dto.getProcessNo());
map.put("workCenter", dto.getWorkCenter());
map.put("processName", dto.getProcessName());
map.put("processDescription", dto.getProcessDescription());
map.put("processControl", dto.getProcessControl());
map.put("activityDuration", dto.getActivityDuration());
map.put("activityUnit", dto.getActivityUnit());
// 数量部分
map.put("unitQuantity", dto.getUnitQuantity());
map.put("batchQuantity", dto.getBatchQuantity());
map.put("firstBatchQuantity", dto.getFirstBatchQuantity());
// 时间字段格式化
map.put("planStartTime", formatDate(dto.getPlanStartTime()));
map.put("planEndTime", formatDate(dto.getPlanEndTime()));
map.put("xuStartTime", formatDate(dto.getXuStartTime()));
map.put("xuEndTime", formatDate(dto.getXuEndTime()));
mapList.add(map);
index++;
}
return mapList;
}
/** /**
* 转换工艺VO为Map列表用于模板 * 转换工艺VO为Map列表用于模板
*/ */
private List<Map<String, Object>> convertRouteDataToMapList(List<ProcessRouteVo> routeDataList) { private List<Map<String, Object>> convertRouteDataToMapList(List<ProcessRouteExcelDTO> routeDataList) {
List<Map<String, Object>> mapList = new ArrayList<>(); List<Map<String, Object>> mapList = new ArrayList<>();
int index = 1; int index = 1;
for (ProcessRouteVo item : routeDataList) { for (ProcessRouteExcelDTO item : routeDataList) {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("index", index); map.put("index", index);
map.put("routeDescription", item.getRouteDescription()); // 生产令号 map.put("routeDescription", item.getRouteDescription()); // 生产令号
@ -1081,10 +1109,10 @@ public class ProcessOrderProController extends BaseController {
map.put("unitQuantity", item.getUnitQuantity()); // 单台数量 map.put("unitQuantity", item.getUnitQuantity()); // 单台数量
map.put("batchQuantity", item.getBatchQuantity()); // 本批数量 map.put("batchQuantity", item.getBatchQuantity()); // 本批数量
map.put("firstBatchQuantity", item.getFirstBatchQuantity()); // 首批数量 map.put("firstBatchQuantity", item.getFirstBatchQuantity()); // 首批数量
map.put("planStartTime", item.getPlanStartTime()); // 计划开始时间 map.put("planStartTime", formatDate(item.getPlanStartTime()));
map.put("planEndTime", item.getPlanEndTime()); // 计划结束时间 map.put("planEndTime", formatDate(item.getPlanEndTime()));
map.put("xuStartTime", item.getXuStartTime()); // 序开始时间 map.put("xuStartTime", formatDate(item.getXuStartTime()));
map.put("xuEndTime", item.getXuEndTime()); // 序结束时间 map.put("xuEndTime", formatDate(item.getXuEndTime()));
mapList.add(map); mapList.add(map);
index++; index++;
} }

View File

@ -27,6 +27,7 @@ import com.ruoyi.system.domain.vo.*;
import com.ruoyi.system.jdmain.rouplan.Model; import com.ruoyi.system.jdmain.rouplan.Model;
import com.ruoyi.system.mapper.BomDetailsMapper; import com.ruoyi.system.mapper.BomDetailsMapper;
import com.ruoyi.system.mapper.MaterialBomMapper; import com.ruoyi.system.mapper.MaterialBomMapper;
import com.ruoyi.system.mapper.ProcessOrderProMapper;
import com.ruoyi.system.mapper.ProcessRouteMapper; import com.ruoyi.system.mapper.ProcessRouteMapper;
import com.ruoyi.system.runner.JdUtil; import com.ruoyi.system.runner.JdUtil;
import com.ruoyi.system.service.IBomDetailsService; import com.ruoyi.system.service.IBomDetailsService;
@ -70,6 +71,7 @@ public class ProcessRouteController extends BaseController {
@Autowired @Autowired
MaterialBomMapper materialBomMapper; MaterialBomMapper materialBomMapper;
private final IBomDetailsService iBomDetailsService; private final IBomDetailsService iBomDetailsService;
private final ProcessOrderProMapper proMapper;
private Long generateUniqueParentId(Long originalId) { private Long generateUniqueParentId(Long originalId) {
return originalId + 1000; return originalId + 1000;
} }
@ -393,7 +395,7 @@ public class ProcessRouteController extends BaseController {
if (!route.isEmpty()){ if (!route.isEmpty()){
return R.fail("项目 "+productionOrderNo+"已导入过工艺 ,请先清空再上传"); return R.fail("项目 "+productionOrderNo+"已导入过工艺 ,请先清空再上传");
} }
if (iProcessRouteService.saveData(result.getList(), list)) { if (iProcessRouteService.saveData(list1, list)) {
return R.ok("上传物料成功"); return R.ok("上传物料成功");
} else { } else {
return R.fail("导入失败"); return R.fail("导入失败");
@ -475,8 +477,9 @@ public class ProcessRouteController extends BaseController {
public void generatePDFs(String rooteProdet, HttpServletResponse response) throws IOException { public void generatePDFs(String rooteProdet, HttpServletResponse response) throws IOException {
// 调用服务层方法生成 ZIP 文件并获取其路径 // 调用服务层方法生成 ZIP 文件并获取其路径
String zipFilePath = iProcessRouteService.generatePDFs(rooteProdet); String zipFilePath = iProcessRouteService.generatePDFs(rooteProdet);
System.out.println("ZIP 文件路径: " + zipFilePath); ProcessOrderPro processOrderPro = proMapper.selectByProjectNumber(rooteProdet);
processOrderPro.setBomStatus(5L);
proMapper.updateById(processOrderPro);
// 读取文件为字节数组 // 读取文件为字节数组
File zipFile = new File(zipFilePath); File zipFile = new File(zipFilePath);
if (!zipFile.exists()) { if (!zipFile.exists()) {

View File

@ -36,16 +36,19 @@ public class BomDetails extends BaseEntity {
*/ */
@JsonProperty("F_HBYT_BJMC") @JsonProperty("F_HBYT_BJMC")
private String partdiagramName; private String partdiagramName;
/** /**
* 父级物料编码 * 父级物料编码
*/ */
@JsonProperty("FMATERIALID.FNumber") @JsonProperty("FMATERIALID.FNumber")
private String fNumber; private String fNumber;
/** /**
* 父级物料名称 * 父级物料名称
*/ */
@JsonProperty("FITEMNAME") @JsonProperty("FITEMNAME")
private String fName; private String fName;
/** /**
* 子项物料单位 * 子项物料单位
*/ */
@ -57,11 +60,13 @@ public class BomDetails extends BaseEntity {
*/ */
@JsonProperty("FMATERIALIDCHILD.FNumber") @JsonProperty("FMATERIALIDCHILD.FNumber")
private String partNumber; private String partNumber;
/** /**
*子项物料名称 *子项物料名称
*/ */
@JsonProperty("FCHILDITEMNAME") @JsonProperty("FCHILDITEMNAME")
private String name; private String name;
/** /**
*属性 *属性
*/ */

View File

@ -86,7 +86,8 @@ public class ImMaterial extends BaseEntity {
/** /**
* 搜索次数 * 搜索次数
*/ */
private Long searchCount; @JsonProperty("F_HBYT_PP")
private String searchCount;
/** /**
* 金蝶修改时间当日 * 金蝶修改时间当日
*/ */

View File

@ -0,0 +1,12 @@
package com.ruoyi.system.domain.dto;
import lombok.Data;
@Data
public class KindegeeLogDTO {
private String projectCode;
private String materialCode;
private String materialName;
private String code;
private String reason;
}

View File

@ -6,8 +6,6 @@ import java.util.Date;
@Data @Data
public class ProcessRouteExcelDTO { public class ProcessRouteExcelDTO {
private Long id; private Long id;
/** /**
@ -35,7 +33,7 @@ public class ProcessRouteExcelDTO {
/** /**
* 单重KG * 单重KG
*/ */
private Double discWeight; private String discWeight;
/** /**
* 材料BOM物料编码 * 材料BOM物料编码
*/ */
@ -103,7 +101,7 @@ public class ProcessRouteExcelDTO {
/** /**
* 单台数量 * 单台数量
*/ */
private Double unitQuantity; private String unitQuantity;
/** /**
* 本批数量 * 本批数量

View File

@ -73,7 +73,7 @@ public class EleMaterialsVo {
/** /**
* 物料值 * 物料值
*/ */
@ExcelProperty(value = "工时") @ExcelProperty(value = "工时")
private String materialValue; private String materialValue;

View File

@ -21,7 +21,7 @@ public class ElecOutDataVO {
private String name; private String name;
/** 数量 */ /** 数量 */
private Integer quantity; private Double quantity;
/** 材料 */ /** 材料 */
private String material; private String material;

View File

@ -0,0 +1,93 @@
package com.ruoyi.system.domain.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 电气物料BOM
* 2025-09-25
*/
@Data
public class ElectricalMaterialBomVO {
/**
* ID
*/
private Long id;
/**
* 生产令号
*/
@ExcelProperty(value = "生产令号")
private String productionOrderNo;
/**
* 生产图号
*/
@ExcelProperty(value = "物料编码")
private String drawingNo;
/**
* 生产名称
*/
@ExcelProperty(value = "物料名称")
private String drawingName;
/**
* 型号
*/
@ExcelProperty(value = "型号")
private String Model;
/**
* 品牌
*/
@ExcelProperty(value = "品牌")
private Double Brand;
/**
* 单台数量
*/
@ExcelProperty(value = "单台数量")
private Double quantity;
/**
* 批次数量
*/
@ExcelProperty(value = "批次数量")
private String batchQuantity;
/**
* 单位
*/
@ExcelProperty(value = "单位")
private Double unit;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 部件名称
*/
@ExcelProperty(value = "上级部件")
private String parentPart;
/**
* 部件图号
*/
@ExcelProperty(value = "上级部件图号")
private String parentDrawingNo;
/**
* 主产品图号
*/
@ExcelProperty(value = "主产品图号")
private String mainProducts;
/**
* 主产品名称
*/
@ExcelProperty(value = "主产品名称")
private String mainProductsName;
}

View File

@ -52,7 +52,7 @@ public class PcRigidChainVo extends BaseEntity
private String box; private String box;
/** 行程mm */ /** 行程mm */
@ExcelProperty( "{V1}") //@ExcelProperty( "{V1}")
private Long journey; private Long journey;
/** 标记号 */ /** 标记号 */

View File

@ -1528,7 +1528,6 @@ public class JdUtil {
needUpdateFields.add("FMATERIALID"); needUpdateFields.add("FMATERIALID");
needUpdateFields.add("FStandHourUnitId"); needUpdateFields.add("FStandHourUnitId");
// 创建 NeedReturnFields 数组
JsonArray needReturnFields = new JsonArray(); JsonArray needReturnFields = new JsonArray();
needReturnFields.add("SubHeadEntity5_FEntryId"); needReturnFields.add("SubHeadEntity5_FEntryId");
needReturnFields.add("FStdLaborProcessTime"); needReturnFields.add("FStdLaborProcessTime");

View File

@ -58,7 +58,7 @@ public interface IProcessOrderProService {
List<ProcessRoute> selectProList(ProcessOrderProBo bo); List<ProcessRoute> selectProList(ProcessOrderProBo bo);
ProcessOrderProBo selectByProjectNumber(String routeDescription); ProcessOrderPro selectByProjectNumber(String routeDescription);
void batchUpdateProjectTimeRanges(); void batchUpdateProjectTimeRanges();
List<ProcessOrderPro> selectByProjectNumbers(Set<String> routeDescSet); List<ProcessOrderPro> selectByProjectNumbers(Set<String> routeDescSet);
@ -78,5 +78,5 @@ public interface IProcessOrderProService {
List<OverdueProjectVo> getOverdueProjects(); List<OverdueProjectVo> getOverdueProjects();
List<ProcessRouteExcelDTO> getRouteAndBomDetail(List<ProductionOrderVo> processDataList,ProcessOrderPro orderPro); List<ProcessRouteExcelDTO> getRouteAndBomDetail(List<ProcessRoute> routlist,List<ProductionOrderVo> processDataList,ProcessOrderPro orderPro);
} }

View File

@ -726,7 +726,7 @@ public class ImMaterialServiceImpl implements IImMaterialService {
*/ */
@Override @Override
public Boolean insertJDMaterial(List<ImMaterial> materialList) { public Boolean insertJDMaterial(List<ImMaterial> materialList) {
if (materialList.size()<0 || materialList.isEmpty()){ if (materialList.isEmpty()){
return false; return false;
} }
return baseMapper.insertBatch(materialList); return baseMapper.insertBatch(materialList);

View File

@ -37,11 +37,9 @@ import java.util.*;
public class MrpResultCheckServiceImpl implements IMrpResultCheckService { public class MrpResultCheckServiceImpl implements IMrpResultCheckService {
private final MrpResultCheckMapper baseMapper; private final MrpResultCheckMapper baseMapper;
private final FigureSaveMapper figureSaveMapper;
private final ProcessOrderProMapper processOrderProMapper; private final ProcessOrderProMapper processOrderProMapper;
private final IMaterialBomService iMaterialBomService; private final IMaterialBomService iMaterialBomService;
private final IProductionOrderService iProductionOrderService; private final IProductionOrderService iProductionOrderService;
private final IBomDetailsService iBomDetailsService;
private final IProcessRouteService iProcessRouteService; private final IProcessRouteService iProcessRouteService;
/** /**
* 查询MRP运算结果复查 * 查询MRP运算结果复查
@ -281,7 +279,8 @@ public class MrpResultCheckServiceImpl implements IMrpResultCheckService {
baseMapper.insert(vo); baseMapper.insert(vo);
} }
processOrderPro.setBomStatus(4L);
processOrderProMapper.updateById(processOrderPro);
} }

View File

@ -2,6 +2,7 @@ package com.ruoyi.system.service.impl;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lowagie.text.Rectangle; import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.PdfReader; import com.lowagie.text.pdf.PdfReader;
@ -28,13 +29,14 @@ import com.ruoyi.system.domain.vo.ProductionOrderVo;
import com.ruoyi.system.listener.FileToZip; import com.ruoyi.system.listener.FileToZip;
import com.ruoyi.system.listener.SmbUtils; import com.ruoyi.system.listener.SmbUtils;
import com.ruoyi.system.mapper.FigureSaveMapper; import com.ruoyi.system.mapper.FigureSaveMapper;
import com.ruoyi.system.mapper.MaterialBomMapper;
import com.ruoyi.system.mapper.ProcessRouteMapper; import com.ruoyi.system.mapper.ProcessRouteMapper;
import com.ruoyi.system.service.*; import com.ruoyi.system.service.*;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.system.domain.bo.ProcessOrderProBo; import com.ruoyi.system.domain.bo.ProcessOrderProBo;
@ -138,6 +140,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
lqw.eq(bo.getProjectEndTime() != null, ProcessOrderPro::getProjectEndTime, bo.getProjectEndTime()); lqw.eq(bo.getProjectEndTime() != null, ProcessOrderPro::getProjectEndTime, bo.getProjectEndTime());
lqw.eq(StringUtils.isNotBlank(bo.getUnit()), ProcessOrderPro::getUnit, bo.getUnit()); lqw.eq(StringUtils.isNotBlank(bo.getUnit()), ProcessOrderPro::getUnit, bo.getUnit());
lqw.eq(bo.getQuantity() != null, ProcessOrderPro::getQuantity, bo.getQuantity()); lqw.eq(bo.getQuantity() != null, ProcessOrderPro::getQuantity, bo.getQuantity());
lqw.eq(bo.getBomStatus() != null, ProcessOrderPro::getBomStatus, bo.getBomStatus());
lqw.eq(bo.getIsEnterpriseStandard() != null, ProcessOrderPro::getIsEnterpriseStandard, bo.getIsEnterpriseStandard()); lqw.eq(bo.getIsEnterpriseStandard() != null, ProcessOrderPro::getIsEnterpriseStandard, bo.getIsEnterpriseStandard());
lqw.eq(bo.getDrawingPath() != null, ProcessOrderPro::getDrawingPath, bo.getDrawingPath()); lqw.eq(bo.getDrawingPath() != null, ProcessOrderPro::getDrawingPath, bo.getDrawingPath());
//按照创建时间排序最新的在顶端 //按照创建时间排序最新的在顶端
@ -245,18 +248,10 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
* @return * @return
*/ */
@Override @Override
public ProcessOrderProBo selectByProjectNumber(String routeDescription) { public ProcessOrderPro selectByProjectNumber(String routeDescription) {
LambdaQueryWrapper<ProcessOrderPro> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<ProcessOrderPro> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ProcessOrderPro::getProductionOrderNo, routeDescription); wrapper.eq(ProcessOrderPro::getProductionOrderNo, routeDescription);
ProcessOrderPro processOrderPro = baseMapper.selectOne(wrapper); return baseMapper.selectOne(wrapper);
ProcessOrderProBo processOrderProBo = new ProcessOrderProBo();
// 添加null检查
if (processOrderPro != null) {
BeanUtils.copyProperties(processOrderPro, processOrderProBo);
}
return processOrderProBo;
} }
@ -288,7 +283,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
// 更新至计划模块中 // 更新至计划模块中
if (earliestStartTime != null && latestEndTime != null) { if (earliestStartTime != null && latestEndTime != null) {
ProcessOrderProBo processOrderPro = selectByProjectNumber(projectNumber); ProcessOrderPro processOrderPro = selectByProjectNumber(projectNumber);
if (processOrderPro != null) { if (processOrderPro != null) {
processOrderPro.setPlanStartTime(earliestStartTime); processOrderPro.setPlanStartTime(earliestStartTime);
@ -359,7 +354,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
pwProductionBill.setProduct(productInfos); pwProductionBill.setProduct(productInfos);
// 6. 调用API // 6. 调用API
return callDrawingApi(pwProductionBill,orderPro); return callDrawingApi(pwProductionBill, orderPro);
} }
@ -533,7 +528,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
datainfo.setG20(String.valueOf(rigidChain.getGTwenty())); datainfo.setG20(String.valueOf(rigidChain.getGTwenty()));
} }
private String callDrawingApi(PwProductionBill pwProductionBill,ProcessOrderProBo orderPro) { private String callDrawingApi(PwProductionBill pwProductionBill, ProcessOrderProBo orderPro) {
try { try {
String drawingDate = JSONObject.toJSONString(pwProductionBill); String drawingDate = JSONObject.toJSONString(pwProductionBill);
log.info("请求出图报文=====>{}", drawingDate); log.info("请求出图报文=====>{}", drawingDate);
@ -557,7 +552,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
// 判断完成条件processstate=4 表示完成 // 判断完成条件processstate=4 表示完成
if ("idle".equals(currentStatus) && processState == 4) { if ("idle".equals(currentStatus) && processState == 4) {
ProcessOrderPro processOrderPro = new ProcessOrderPro(); ProcessOrderPro processOrderPro = new ProcessOrderPro();
BeanUtils.copyProperties(orderPro,processOrderPro); BeanUtils.copyProperties(orderPro, processOrderPro);
processOrderPro.setBomStatus(1L);// processOrderPro.setBomStatus(1L);//
baseMapper.updateById(processOrderPro); baseMapper.updateById(processOrderPro);
@ -1106,6 +1101,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
/** /**
* 递归删除目录及其内容 * 递归删除目录及其内容
*
* @param directory 要删除的目录 * @param directory 要删除的目录
* @throws IOException 删除失败时抛出异常 * @throws IOException 删除失败时抛出异常
*/ */
@ -1128,47 +1124,112 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
} }
} }
} }
/** /**
* 将工艺部分 材料BOM部分 合并成ProcessRouteExcelDTO * 将工艺部分 材料BOM部分 合并成ProcessRouteExcelDTO
*
* @return * @return
*/ */
//@Override @Override
public List<ProcessRouteExcelDTO> getRouteAndBomDetail1(List<ProductionOrderVo> processDataList, public List<ProcessRouteExcelDTO> getRouteAndBomDetail(List<ProcessRoute> routlist,List<ProductionOrderVo> processDataList, ProcessOrderPro orderPro) {
ProcessOrderPro orderPro) {
String proRoot = orderPro.getProductionOrderNo(); String proRoot = orderPro.getProductionOrderNo();
// 查出所有工艺路线和BOM // 查出所有工艺路线和BOM
List<ProcessRoute> allRoutes = iProcessRouteService.selectByProjectNumber(proRoot); List<ProcessRoute> allRoutes = iProcessRouteService.selectByProjectNumber(proRoot);
List<MaterialBom> allBoms = materialBomService.selectByProCode(proRoot); List<MaterialBom> allBoms = materialBomService.selectByProCode(proRoot);
// 建立 routlist Map 方便查找
Map<String, ProcessRoute> routeMap1 = routlist.stream()
.filter(r -> r.getMaterialCode() != null)
.collect(Collectors.toMap(ProcessRoute::getMaterialCode, r -> r));
// 合并数据
for (ProcessRoute route : allRoutes) {
ProcessRoute source = routeMap1.get(route.getMaterialCode());
if (source != null) {
copyPropertiesIgnoreNull(source, route); // routlist 的非空字段补充 allRoutes
}
}
List<ProcessRouteExcelDTO> resultList = new ArrayList<>(); List<ProcessRouteExcelDTO> resultList = new ArrayList<>();
for (ProductionOrderVo orderVo : processDataList) { // 规范化 key
String materialCode = orderVo.getDrawingNo(); // 这里我假设 drawingNo == materialCode Function<String, String> normalize = s -> s == null ? "" : s.trim().toUpperCase();
// materialCode 过滤 // materialCode 分组工艺路线
List<ProcessRoute> processRoutes = allRoutes.stream() Map<String, List<ProcessRoute>> routeMap = allRoutes.stream()
.filter(r -> materialCode.equals(r.getMaterialCode())) .collect(Collectors.groupingBy(r -> normalize.apply(r.getMaterialCode())));
.collect(Collectors.toList());
List<MaterialBom> materialBoms = allBoms.stream() // parentMaterialCode 分组BOM
.filter(b -> materialCode.equals(b.getParentMaterialCode())) Map<String, List<MaterialBom>> bomMap = allBoms.stream()
.collect(Collectors.toList()); .collect(Collectors.groupingBy(b -> normalize.apply(b.getParentMaterialCode())));
// 把订单数据做成 Map
Map<String, ProductionOrderVo> orderMap = processDataList.stream()
.collect(Collectors.toMap(vo -> normalize.apply(vo.getDrawingNo()), vo -> vo, (a, b) -> a));
// 合并 material keys
LinkedHashSet<String> materialKeys = new LinkedHashSet<>();
materialKeys.addAll(routeMap.keySet());
orderMap.keySet().stream()
.filter(key -> !materialKeys.contains(key))
.forEach(materialKeys::add);
for (String key : materialKeys) {
List<ProcessRoute> processRoutes = routeMap.getOrDefault(key, Collections.emptyList());
List<MaterialBom> materialBoms = bomMap.getOrDefault(key, Collections.emptyList());
ProductionOrderVo orderVo = orderMap.get(key);
// 优先从 processRoutes 取值其次才用 orderVo最后才用 BOM key
String originalMaterialCode = !processRoutes.isEmpty()
? processRoutes.get(0).getMaterialCode().trim()
: (orderVo != null
? (orderVo.getDrawingNo() != null ? orderVo.getDrawingNo().trim() : null)
: (!materialBoms.isEmpty()
? (materialBoms.get(0).getParentMaterialCode() != null ? materialBoms.get(0).getParentMaterialCode().trim() : null)
: key));
String originalMaterialName = !processRoutes.isEmpty()
? (processRoutes.get(0).getMaterialName() != null ? processRoutes.get(0).getMaterialName().trim() : null)
: (orderVo != null ? (orderVo.getDrawingName() != null ? orderVo.getDrawingName().trim() : null) : null);
String originalMaterial = !processRoutes.isEmpty()
? (processRoutes.get(0).getMaterial() != null ? processRoutes.get(0).getMaterial().trim() : null)
: (orderVo != null ? (orderVo.getMaterial() != null ? orderVo.getMaterial().trim() : null) : null);
Double originalUnitWeight = !processRoutes.isEmpty() ? processRoutes.get(0).getDiscWeight() : (orderVo != null ? orderVo.getSingleWeight() : null);
// 🔹 新增两个数量字段
Double unitQuantity = !processRoutes.isEmpty()
? processRoutes.get(0).getUnitQuantity()
: (orderVo != null ? orderVo.getQuantity() : null);
Double batchQuantity = !processRoutes.isEmpty()
? (processRoutes.get(0).getBatchQuantity() != null ? processRoutes.get(0).getBatchQuantity() : 0)
: (orderVo != null
? (orderVo.getBatchQuantity() != null
? Double.valueOf(orderVo.getBatchQuantity())
: null)
: null);
// 对齐到最长列表
int maxSize = Math.max(processRoutes.size(), materialBoms.size()); int maxSize = Math.max(processRoutes.size(), materialBoms.size());
if (maxSize == 0 && orderVo != null) maxSize = 1;
for (int i = 0; i < maxSize; i++) { for (int i = 0; i < maxSize; i++) {
ProcessRouteExcelDTO dto = new ProcessRouteExcelDTO(); ProcessRouteExcelDTO dto = new ProcessRouteExcelDTO();
// 订单基础信息 // 补充名称/材质/单重字段
dto.setRouteDescription(orderVo.getProductionOrderNo()); dto.setMaterialCode(originalMaterialCode);
dto.setMaterialCode(orderVo.getDrawingNo()); dto.setMaterialName(originalMaterialName);
dto.setMaterialName(orderVo.getDrawingName()); dto.setMaterial(originalMaterial);
dto.setMaterial(orderVo.getMaterial()); dto.setDiscWeight(String.valueOf(originalUnitWeight));
dto.setDiscWeight(orderVo.getSingleWeight()); dto.setUnitQuantity(String.valueOf(unitQuantity));
dto.setUnitQuantity(orderVo.getQuantity()); dto.setBatchQuantity(String.valueOf(batchQuantity));
dto.setBatchQuantity(orderVo.getBatchQuantity());
// 订单数量信息
if (orderVo != null) {
dto.setRouteDescription(orderVo.getProductionOrderNo());
dto.setUnitQuantity(String.valueOf(orderVo.getQuantity()));
dto.setBatchQuantity(orderVo.getBatchQuantity());
}
// 工艺部分 // 工艺部分
if (i < processRoutes.size()) { if (i < processRoutes.size()) {
@ -1180,8 +1241,8 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
dto.setProcessControl(route.getProcessControl()); dto.setProcessControl(route.getProcessControl());
dto.setActivityDuration(route.getActivityDuration()); dto.setActivityDuration(route.getActivityDuration());
dto.setActivityUnit(route.getActivityUnit()); dto.setActivityUnit(route.getActivityUnit());
dto.setXuEndTime(route.getXuEndTime());
dto.setXuStartTime(route.getXuStartTime()); dto.setXuStartTime(route.getXuStartTime());
dto.setXuEndTime(route.getXuEndTime());
} }
// BOM 部分 // BOM 部分
@ -1191,132 +1252,42 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
dto.setRawMaterialName(bom.getMaterialName()); dto.setRawMaterialName(bom.getMaterialName());
dto.setBomMaterial(bom.getMaterialType()); dto.setBomMaterial(bom.getMaterialType());
dto.setBomUnit(bom.getUnit()); dto.setBomUnit(bom.getUnit());
dto.setDiscUsage(bom.getQuantity());
// 单位转换如果单位为mm则数值乘以1000
String quantity = bom.getQuantity();
if ("mm".equals(bom.getUnit()) && quantity != null) {
try {
BigDecimal originalValue = new BigDecimal(quantity);
BigDecimal convertedValue = originalValue.multiply(new BigDecimal("1000"));
dto.setDiscUsage(convertedValue.toString());
} catch (NumberFormatException e) {
// 如果转换失败使用原值
dto.setDiscUsage(quantity);
} }
resultList.add(dto);
}
}
return resultList;
}
/**
* 将工艺部分 材料BOM部分 合并成ProcessRouteExcelDTO
* @return
*/
@Override
public List<ProcessRouteExcelDTO> getRouteAndBomDetail(List<ProductionOrderVo> processDataList,
ProcessOrderPro orderPro) {
String proRoot = orderPro.getProductionOrderNo();
// 查出所有工艺路线和BOM
List<ProcessRoute> allRoutes = iProcessRouteService.selectByProjectNumber(proRoot);
List<MaterialBom> allBoms = materialBomService.selectByProCode(proRoot);
List<ProcessRouteExcelDTO> resultList = new ArrayList<>();
// 规范化 keytrim + upper避免空格/大小写导致匹配失败
Function<String, String> normalize = s -> s == null ? "" : s.trim().toUpperCase();
// materialCode 分组工艺路线
Map<String, List<ProcessRoute>> routeMap = allRoutes.stream()
.collect(Collectors.groupingBy(r -> normalize.apply(r.getMaterialCode())));
// parentMaterialCode 分组BOM parent
Map<String, List<MaterialBom>> bomMap = allBoms.stream()
.collect(Collectors.groupingBy(b -> normalize.apply(b.getParentMaterialCode())));
// 把订单数据做成 Mapkey = drawingNo 规范化
Map<String, ProductionOrderVo> orderMap = processDataList.stream()
.collect(Collectors.toMap(vo -> normalize.apply(vo.getDrawingNo()), vo -> vo, (a, b) -> a));
// 先把 routeMap key 加入保证 processRoutes 为基础再补上 orderMap 中但不在 routeMap 的物料
LinkedHashSet<String> materialKeys = new LinkedHashSet<>();
materialKeys.addAll(routeMap.keySet()); // 以工艺路线为主序
orderMap.keySet().stream()
.filter(key -> !materialKeys.contains(key))
.forEach(materialKeys::add); // 补充仅在订单里的物料
// 遍历每个物料编码规范化 key
for (String key : materialKeys) {
List<ProcessRoute> processRoutes = routeMap.getOrDefault(key, Collections.emptyList());
List<MaterialBom> materialBoms = bomMap.getOrDefault(key, Collections.emptyList());
ProductionOrderVo orderVo = orderMap.get(key); // 可能为 null
// 用于显示在 DTO 中的原始物料编码未规范化的形式
String originalMaterialCode = null;
String originalMaterialName = null;
String originalMaterial = null;
String originalDiscWeight = null;
if (orderVo != null) {
originalMaterialCode = orderVo.getDrawingNo();
originalMaterialName = orderVo.getDrawingName();
originalMaterial = orderVo.getMaterial();
originalDiscWeight = String.valueOf(orderVo.getSingleWeight());
} else if (!processRoutes.isEmpty()) {
originalMaterialCode = processRoutes.get(0).getMaterialCode();
} else if (!materialBoms.isEmpty()) {
originalMaterialCode = materialBoms.get(0).getParentMaterialCode();
} else { } else {
originalMaterialCode = key; // 退路用规范化 key dto.setDiscUsage(quantity);
} }
// processRoutes 为主行数 = max(processRoutes.size(), materialBoms.size())
int maxSize = Math.max(processRoutes.size(), materialBoms.size());
// 如果两边都为空但有订单order-only也至少输出一行
if (maxSize == 0 && orderVo != null) {
maxSize = 1;
} }
for (int i = 0; i < maxSize; i++) {
ProcessRouteExcelDTO dto = new ProcessRouteExcelDTO();
// 订单基础信息有就填
if (orderVo != null) {
dto.setRouteDescription(orderVo.getProductionOrderNo());
dto.setMaterialCode(orderVo.getDrawingNo());
dto.setMaterialName(orderVo.getDrawingName());
dto.setMaterial(orderVo.getMaterial());
dto.setDiscWeight(orderVo.getSingleWeight());
dto.setUnitQuantity(orderVo.getQuantity());
dto.setBatchQuantity(orderVo.getBatchQuantity());
} else {
// 若无订单则至少把 materialCode 放入显示用原始值
dto.setMaterialCode(originalMaterialCode);
dto.setMaterialName(originalMaterialName);
dto.setMaterial(originalMaterial);
dto.setDiscUsage(originalDiscWeight);
}
// 工艺部分有就填
if (i < processRoutes.size()) {
ProcessRoute route = processRoutes.get(i);
dto.setProcessNo(route.getProcessNo());
dto.setProcessName(route.getProcessName());
dto.setWorkCenter(route.getWorkCenter());
dto.setProcessDescription(route.getProcessDescription());
dto.setProcessControl(route.getProcessControl());
dto.setActivityDuration(route.getActivityDuration());
dto.setActivityUnit(route.getActivityUnit());
dto.setXuEndTime(route.getXuEndTime());
dto.setXuStartTime(route.getXuStartTime());
}
// BOM 部分 parentMaterialCode 为匹配依据
if (i < materialBoms.size()) {
MaterialBom bom = materialBoms.get(i);
dto.setRawMaterialCode(bom.getMaterialCode());
dto.setRawMaterialName(bom.getMaterialName());
dto.setBomMaterial(bom.getMaterialType());
dto.setBomUnit(bom.getUnit());
dto.setDiscUsage(bom.getQuantity());
}
resultList.add(dto); resultList.add(dto);
} }
} }
return resultList; return resultList;
} }
public static String[] getNullPropertyNames(Object source) {
BeanWrapper src = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<>();
for (java.beans.PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
}
return emptyNames.toArray(new String[0]);
}
public static void copyPropertiesIgnoreNull(Object src, Object target) {
BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
}
} }

View File

@ -569,19 +569,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
saveBomDetails(bomDetailsVos); saveBomDetails(bomDetailsVos);
List<ProcessRoute> routeArrayList = new ArrayList<>(); List<ProcessRoute> routeArrayList = new ArrayList<>();
Map<String, Double> inventoryCache = new HashMap<>(); Map<String, Double> inventoryCache = new HashMap<>();
// 批量查询所有需要的库存信息
/* for (ProcessRoute processRoute : processRoutes) {
String materialCode = processRoute.getMaterialCode();
if (!inventoryCache.containsKey(materialCode)) {
try {
Double kucun = JdUtil.getKeyong(materialCode);
inventoryCache.put(materialCode, kucun);
} catch (Exception e) {
log.error("查询库存失败: {}", materialCode, e);
inventoryCache.put(materialCode, 0.0);
}
}
}*/
boolean allEmpty = processRoutes.stream().allMatch(route -> route.getProcessNo() == null && route.getProcessName() == null); boolean allEmpty = processRoutes.stream().allMatch(route -> route.getProcessNo() == null && route.getProcessName() == null);
//获取工艺中所有的时间 挑选出最早的时间和最晚的时间 //获取工艺中所有的时间 挑选出最早的时间和最晚的时间
@ -622,8 +610,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
for (ProcessRoute processRoute : processRoutes) { for (ProcessRoute processRoute : processRoutes) {
String materialCode = processRoute.getMaterialCode(); String materialCode = processRoute.getMaterialCode();
Double kucun = inventoryCache.get(materialCode); Double kucun = inventoryCache.get(materialCode);
boolean isDuplicateWelding = "组焊件".equals(processRoute.getMaterial()) boolean isDuplicateWelding = "组焊件".equals(processRoute.getMaterial()) && duplicateWeldingMaterials.contains(materialCode);
&& duplicateWeldingMaterials.contains(materialCode);
if (isDuplicateWelding && processedWeldingMaterials.contains(materialCode)) { if (isDuplicateWelding && processedWeldingMaterials.contains(materialCode)) {
continue; continue;
@ -663,7 +650,6 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
defaultRoute.setProcessControl(null); defaultRoute.setProcessControl(null);
defaultRoute.setActivityDuration(null); defaultRoute.setActivityDuration(null);
defaultRoute.setActivityUnit(""); defaultRoute.setActivityUnit("");
defaultRoute.setFirstBatchQuantity(kucun);
defaultRoute.setCreateTime(new Date()); defaultRoute.setCreateTime(new Date());
defaultRoute.setUpdateTime(new Date()); defaultRoute.setUpdateTime(new Date());
routeArrayList.add(defaultRoute); routeArrayList.add(defaultRoute);
@ -696,11 +682,14 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
} }
} else { } else {
for (ProcessRoute processRoute : processRoutes) { for (ProcessRoute processRoute : processRoutes) {
if (processRoute.getProcessNo() != null || processRoute.getProcessName() != null) { if (processRoute.getProcessNo() != null
||processRoute.getWorkCenter()!= null
||processRoute.getProcessName() != null
||processRoute.getMaterial().equals("总装部件")) {
processRoute.setActivityUnit(""); processRoute.setActivityUnit("");
processRoute.setCreateTime(new Date()); processRoute.setCreateTime(new Date());
processRoute.setUpdateTime(new Date()); processRoute.setUpdateTime(new Date());
processRoute.setFirstBatchQuantity(processRoute.getFirstBatchQuantity()); processRoute.setBatchQuantity(processRoute.getBatchQuantity());
processRoute.setUnitQuantity(processRoute.getUnitQuantity()); processRoute.setUnitQuantity(processRoute.getUnitQuantity());
routeArrayList.add(processRoute); routeArrayList.add(processRoute);
} }

View File

@ -158,9 +158,8 @@ public class SafetyStockServiceImpl implements ISafetyStockService {
public Boolean isSafeCode(String materialCode) { public Boolean isSafeCode(String materialCode) {
LambdaQueryWrapper<SafetyStock> safetyStockLambdaQueryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SafetyStock> safetyStockLambdaQueryWrapper = new LambdaQueryWrapper<>();
safetyStockLambdaQueryWrapper.eq(SafetyStock::getMaterialCode,materialCode); safetyStockLambdaQueryWrapper.eq(SafetyStock::getMaterialCode,materialCode);
SafetyStock safetyStock = baseMapper.selectOne(safetyStockLambdaQueryWrapper); List<SafetyStock> safetyStocks = baseMapper.selectList(safetyStockLambdaQueryWrapper);
return safetyStock != null; return !safetyStocks.isEmpty();
} }
/** /**

View File

@ -79,7 +79,7 @@ public class WorkProcedureServiceImpl implements IWorkProcedureService {
parentTask.setParent(null); parentTask.setParent(null);
// 获取工艺订单信息 // 获取工艺订单信息
ProcessOrderProBo processOrderProBo = iProcessOrderProService.selectByProjectNumber(processRoute.getRouteDescription()); ProcessOrderPro processOrderProBo = iProcessOrderProService.selectByProjectNumber(processRoute.getRouteDescription());
Date start = processOrderProBo.getPlanStartTime(); Date start = processOrderProBo.getPlanStartTime();
Date end = processOrderProBo.getPlanEndTime(); Date end = processOrderProBo.getPlanEndTime();