采购订单列表推送至企业微信更新20250916
This commit is contained in:
parent
d5a75728b9
commit
6abb92c321
@ -7,10 +7,12 @@ import org.apache.poi.xssf.usermodel.XSSFCell;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -22,27 +24,29 @@ import java.util.Map;
|
||||
public class ExcelTemplateProc {
|
||||
|
||||
/**
|
||||
* @param templateFileName
|
||||
* @param exportFilePathAndName
|
||||
* @param staticDataMap
|
||||
* @param dynamicDataMappingList
|
||||
* @return void
|
||||
* @description: 根据模版导出Excel入口
|
||||
* @author susu
|
||||
* @date 2024/2/20
|
||||
* 根据模版导出Excel入口
|
||||
* @param templateFileName 模板文件路径,可以是classpath路径 或 本地绝对路径
|
||||
* @param exportFilePathAndName 导出文件完整路径
|
||||
* @param staticDataMap 静态数据
|
||||
* @param dynamicDataMappingList 动态数据
|
||||
*/
|
||||
public static void doExportExcelByTemplateProc(String templateFileName, String exportFilePathAndName,
|
||||
public static void doExportExcelByTemplateProc(String templateFileName,
|
||||
String exportFilePathAndName,
|
||||
Map<String, Object> staticDataMap,
|
||||
List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
|
||||
/**
|
||||
* 1. 从resources下加载模板并替换
|
||||
* 使用 ResourceUtils 加载文件
|
||||
*/
|
||||
File file = ResourceUtils.getFile("classpath:"+templateFileName);
|
||||
InputStream inputStream = new FileInputStream(file);
|
||||
|
||||
InputStream inputStream;
|
||||
|
||||
if (templateFileName.startsWith("/") || templateFileName.contains(":")) {
|
||||
// 绝对路径 (Windows: D:/... Linux: /opt/...)
|
||||
inputStream = Files.newInputStream(new File(templateFileName).toPath());
|
||||
} else {
|
||||
// classpath 路径
|
||||
ClassPathResource resource = new ClassPathResource(templateFileName);
|
||||
inputStream = resource.getInputStream();
|
||||
}
|
||||
|
||||
Workbook workbook = dealAllSheetsByTemplate(inputStream, staticDataMap, dynamicDataMappingList);
|
||||
// 2. 保存到本地
|
||||
saveExportFile(workbook, exportFilePathAndName);
|
||||
}
|
||||
|
||||
@ -87,15 +91,15 @@ public class ExcelTemplateProc {
|
||||
Map<String, Object> staticDataMap,
|
||||
List<DynamicDataMapping> dynamicDataMappingList) throws IOException {
|
||||
XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
|
||||
|
||||
|
||||
|
||||
|
||||
// 处理所有sheet页
|
||||
for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
|
||||
XSSFSheet sheet = workbook.getSheetAt(sheetIndex);
|
||||
// 按模板处理sheet页
|
||||
dealSheetDataByTemplate(sheet, staticDataMap, dynamicDataMappingList);
|
||||
}
|
||||
|
||||
|
||||
return workbook;
|
||||
}
|
||||
|
||||
@ -134,7 +138,7 @@ public class ExcelTemplateProc {
|
||||
if (row == null) {
|
||||
continue; // 跳过空行
|
||||
}
|
||||
|
||||
|
||||
// 添加调试信息:检查每一行是否有静态数据占位符
|
||||
if (row.getFirstCellNum() != -1 && row.getLastCellNum() != -1) {
|
||||
for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
|
||||
@ -147,10 +151,10 @@ public class ExcelTemplateProc {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 先处理静态数据,再处理动态数据
|
||||
dealTemplateDataRow(row, null, staticDataMap);
|
||||
|
||||
|
||||
DynamicDataMapping dynamicDataMapping = getDynamicRowDataByMatch(row, dynamicDataMappingList);
|
||||
if (dynamicDataMapping != null) {
|
||||
i = getTemplateLastRowIndexAfterDealTemplate(sheet, i, dynamicDataMapping);
|
||||
@ -177,21 +181,21 @@ public class ExcelTemplateProc {
|
||||
if (dataMap == null || row == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int firstCellNum = row.getFirstCellNum();
|
||||
int lastCellNum = row.getLastCellNum();
|
||||
|
||||
|
||||
// 检查是否有有效的单元格范围
|
||||
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 添加调试信息:显示静态数据处理
|
||||
if (dataPrefix == null || dataPrefix.isEmpty()) {
|
||||
System.out.println("开始处理静态数据行: " + row.getRowNum() + ", dataMap=" + dataMap.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for (int i = firstCellNum; i < lastCellNum; i++) {
|
||||
XSSFCell cell = row.getCell(i);
|
||||
if (cell != null) {
|
||||
@ -224,16 +228,16 @@ public class ExcelTemplateProc {
|
||||
if (StringUtils.isEmpty(cellValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
boolean flag = false;
|
||||
dataPrefix = StringUtils.isEmpty(dataPrefix) ? "" : (dataPrefix + ".");
|
||||
for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
|
||||
// 循环所有,因为可能一行有多个占位符
|
||||
String cellTemplateStr = "{{" + dataPrefix + entry.getKey() + "}}";
|
||||
|
||||
|
||||
|
||||
|
||||
if (cellValue.contains(cellTemplateStr)) {
|
||||
// 替换模版中单元格的数据
|
||||
String replacementValue = entry.getValue() == null ? "" : entry.getValue().toString();
|
||||
@ -267,29 +271,29 @@ public class ExcelTemplateProc {
|
||||
if (dynamicDataMappingList == null || dynamicDataMappingList.size() < 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// 检查行是否为空
|
||||
if (row == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
int firstCellNum = row.getFirstCellNum();
|
||||
int lastCellNum = row.getLastCellNum();
|
||||
|
||||
|
||||
// 检查是否有有效的单元格范围
|
||||
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
for (int j = firstCellNum; j < lastCellNum; j++) {
|
||||
XSSFCell cell = row.getCell(j);
|
||||
if (cell == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
String value = cell.getStringCellValue();
|
||||
if (value != null) {
|
||||
|
||||
|
||||
for (DynamicDataMapping dynamicData : dynamicDataMappingList) {
|
||||
if (value.startsWith("{{" + dynamicData.getDataId() + ".")) {
|
||||
return dynamicData;
|
||||
@ -361,20 +365,20 @@ public class ExcelTemplateProc {
|
||||
if (row == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int firstCellNum = row.getFirstCellNum();
|
||||
int lastCellNum = row.getLastCellNum();
|
||||
|
||||
|
||||
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (int j = firstCellNum; j < lastCellNum; j++) {
|
||||
XSSFCell cell = row.getCell(j);
|
||||
if (cell == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
String value = cell.getStringCellValue();
|
||||
if (value != null && value.contains("{{") && value.contains("}}")) {
|
||||
return true;
|
||||
@ -390,24 +394,24 @@ public class ExcelTemplateProc {
|
||||
if (dynamicDataMappingList == null || dynamicDataMappingList.size() < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (row == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int firstCellNum = row.getFirstCellNum();
|
||||
int lastCellNum = row.getLastCellNum();
|
||||
|
||||
|
||||
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (int j = firstCellNum; j < lastCellNum; j++) {
|
||||
XSSFCell cell = row.getCell(j);
|
||||
if (cell == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
String value = cell.getStringCellValue();
|
||||
if (value != null) {
|
||||
for (DynamicDataMapping dynamicData : dynamicDataMappingList) {
|
||||
@ -427,20 +431,20 @@ public class ExcelTemplateProc {
|
||||
if (row == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int firstCellNum = row.getFirstCellNum();
|
||||
int lastCellNum = row.getLastCellNum();
|
||||
|
||||
|
||||
if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int j = firstCellNum; j < lastCellNum; j++) {
|
||||
XSSFCell cell = row.getCell(j);
|
||||
if (cell == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
String value = cell.getStringCellValue();
|
||||
if (value != null && value.contains("{{") && value.contains("}}")) {
|
||||
// 清理动态数据占位符,保留静态内容
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,9 @@ package com.ruoyi.system.controller;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
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.JsonArray;
|
||||
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.EditGroup;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.result.BOMUploadResult;
|
||||
import com.ruoyi.common.utils.JdUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.domain.BomDetails;
|
||||
import com.ruoyi.system.domain.FigureSave;
|
||||
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.ProcessOrderProBo;
|
||||
import com.ruoyi.system.domain.dto.JdValidateBomDTO;
|
||||
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.ElectricalMaterialBomVO;
|
||||
import com.ruoyi.system.mapper.FigureSaveMapper;
|
||||
import com.ruoyi.system.mapper.ProcessOrderProMapper;
|
||||
import com.ruoyi.system.runner.JdUtil;
|
||||
@ -49,6 +56,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
import static org.aspectj.bridge.MessageUtil.fail;
|
||||
@ -354,12 +362,13 @@ public class BomDetailsController extends BaseController {
|
||||
@PostMapping("/updateFBMaterial")
|
||||
public R updateFBMaterial(@RequestBody List<Map<String, String>> bomDetailParams) {
|
||||
List<BomDetails> bomDetailsList = new ArrayList<>();
|
||||
Set<String> processedMaterials = new HashSet<>(); // 用于跟踪已处理的物料编码
|
||||
List<KindegeeLogDTO> logDTOS = new ArrayList<>();
|
||||
List<String> failedMaterials = new ArrayList<>(); // 用于跟踪处理失败的物料
|
||||
String totalWeight = "";
|
||||
// 遍历前端传来的数据
|
||||
for (Map<String, String> param : bomDetailParams) {
|
||||
String fnumber = param.get("fnumber"); // 物料编码
|
||||
String fname = param.get("fname"); // 物料编码
|
||||
totalWeight = param.get("totalWeight"); // 生产令号
|
||||
|
||||
// 根据物料编码和生产令号查询
|
||||
@ -367,15 +376,9 @@ public class BomDetailsController extends BaseController {
|
||||
log.info("处理物料编码: {}, 生产令号: {}", fnumber, totalWeight);
|
||||
if (bomDetails != null && !bomDetails.isEmpty()) {
|
||||
//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) {
|
||||
// 获取工艺表中的非委外工时
|
||||
Double fbWorkTime = iProcessRouteService.getFbWorkTime(material);
|
||||
@ -383,7 +386,6 @@ public class BomDetailsController extends BaseController {
|
||||
if (material.getPartNumber() != null && material.getName() != null && material.getUnitWeight().equals("否")) {
|
||||
String state = determineState(material);
|
||||
log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName());
|
||||
|
||||
try {
|
||||
int result = loadMaterialPreservation(material, state, fbWorkTime);
|
||||
if (result == 1) {
|
||||
@ -405,69 +407,179 @@ public class BomDetailsController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
// 保存物料清单之前进行BOM校验
|
||||
if (validateBOM(fnumber, bomDetails)) {
|
||||
failedMaterials.add(fnumber);
|
||||
// 第二步:BOM校验和上传(在循环外部)
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
KindegeeLogDTO logDTO = new KindegeeLogDTO();
|
||||
logDTO.setProjectCode(bo.getProductionOrderNo());
|
||||
logDTO.setMaterialCode(fnumber);
|
||||
logDTO.setMaterialName(fname);
|
||||
logDTO.setCode("200");
|
||||
logDTO.setReason("BOM已存在且一致");
|
||||
logDTOS.add(logDTO);
|
||||
log.info("BOM已存在且一致,物料编码: {},跳过保存", fnumber);
|
||||
}
|
||||
|
||||
// 物料清单保存方法
|
||||
FBloadBillOfMaterialsPreservation(bomDetails, bo);
|
||||
bomDetailsList.addAll(bomDetails);
|
||||
}
|
||||
}
|
||||
//更新项目进度
|
||||
ProcessOrderProBo processOrderProBo = iProcessOrderProService.selectByProjectNumber(totalWeight);
|
||||
ProcessOrderPro processOrderProBo = iProcessOrderProService.selectByProjectNumber(totalWeight);
|
||||
|
||||
processOrderProBo.setDrawingType( JSONUtil.toJsonStr(logDTOS));
|
||||
processOrderProBo.setBomStatus(2L);
|
||||
processOrderProMapper.selectById(processOrderProBo);
|
||||
processOrderProMapper.updateById(processOrderProBo);
|
||||
// 返回处理结果
|
||||
return R.ok("成功", bomDetailsList);
|
||||
|
||||
}
|
||||
|
||||
private boolean validateBOM(String fnumber, List<BomDetails> bomDetails) {
|
||||
List<JdValidateBomDTO> JDBomList = JdUtil.getSelectBomList(fnumber);
|
||||
|
||||
// 1. 判断BOM是否为空
|
||||
if (JDBomList == null || JDBomList.isEmpty()) {
|
||||
log.error("未在金蝶中找到相同的BOM,需要上传,物料编码: {}", fnumber);
|
||||
return false; // BOM为空,需要上传
|
||||
log.error("未在金蝶中找到相同的BOM,需要上传,物料编码: {}", fnumber);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (JdValidateBomDTO jdBom : JDBomList) {
|
||||
// 3. 检查子项数量是否一致
|
||||
if (jdBom.getChilds().size() != bomDetails.size()) {
|
||||
continue; // 数量不一致,跳过这个BOM,继续检查下一个
|
||||
// 子项排序:按 PartNumber -> Name -> PartdiagramCode -> PartdiagramName 保证顺序唯一
|
||||
bomDetails.sort(Comparator.comparing(BomDetails::getPartNumber, Comparator.nullsFirst(String::compareTo))
|
||||
.thenComparing(BomDetails::getName, Comparator.nullsFirst(String::compareTo))
|
||||
.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;
|
||||
for (int i = 0; i < jdBom.getChilds().size(); i++) {
|
||||
JdChildDTO jdChild = jdBom.getChilds().get(i);
|
||||
List<String> mismatchDetails = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < childs.size(); i++) {
|
||||
JdChildDTO jdChild = childs.get(i);
|
||||
BomDetails inputBomDetail = bomDetails.get(i);
|
||||
|
||||
// 比较物料编码和名称
|
||||
if (!jdChild.getPartNumber().equals(inputBomDetail.getPartNumber()) || !jdChild.getName().equals(inputBomDetail.getName())) {
|
||||
isMatch = false;
|
||||
break;
|
||||
List<String> itemMismatches = new ArrayList<>();
|
||||
|
||||
// 字符串比较(null/空格统一处理)
|
||||
if (!equalsStr(jdChild.getPartNumber(), inputBomDetail.getPartNumber())) {
|
||||
itemMismatches.add(String.format("PartNumber [金蝶:'%s' vs 输入:'%s']",
|
||||
jdChild.getPartNumber(), inputBomDetail.getPartNumber()));
|
||||
}
|
||||
|
||||
// 比较分子和分母
|
||||
if (!jdChild.getDenominator().equals(inputBomDetail.getDenominator()) || !jdChild.getQuantity().equals(inputBomDetail.getQuantity())) {
|
||||
/* if (!equalsStr(jdChild.getName(), inputBomDetail.getName())) {
|
||||
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;
|
||||
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) {
|
||||
// 找到匹配的BOM,无需上传
|
||||
log.info("BOM完全相同,物料编码: {},无需上传", fnumber);
|
||||
return true;
|
||||
return true; // 找到匹配BOM
|
||||
}
|
||||
}
|
||||
|
||||
// 所有BOM都不匹配,需要上传
|
||||
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物料清单保存
|
||||
public void FBloadBillOfMaterialsPreservation(List<BomDetails> bomlist, ProcessOrderProBo bo) {
|
||||
public BOMUploadResult FBloadBillOfMaterialsPreservation(List<BomDetails> bomlist, ProcessOrderPro bo) {
|
||||
|
||||
BomDetails bomDetails1 = bomlist.get(0);
|
||||
int verification = isMaterialVerification(bomDetails1.getFNumber(), bomDetails1.getFName());
|
||||
@ -648,7 +760,7 @@ public class BomDetailsController extends BaseController {
|
||||
List<JsonObject> fTreeEntityList = new ArrayList<>();
|
||||
for (BomDetails details : bomlist) {
|
||||
if (bomlist.isEmpty()) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
// 创建FTreeEntity对象,并加入FTreeEntity数组
|
||||
JsonObject fTreeEntityItem = new JsonObject();
|
||||
@ -673,7 +785,6 @@ public class BomDetailsController extends BaseController {
|
||||
}
|
||||
fTreeEntityItem.addProperty("FSupplyType", supplyType);
|
||||
}
|
||||
|
||||
fTreeEntityItem.addProperty("FMATERIALTYPE", "1");
|
||||
// 创建FMATERIALIDCHILD对象,并加入FTreeEntity
|
||||
JsonObject fMaterialIdChild = new JsonObject();
|
||||
@ -708,30 +819,23 @@ public class BomDetailsController extends BaseController {
|
||||
fTreeEntityItem.add("FOWNERID", FOWNERID);
|
||||
FOWNERID.addProperty("FNumber", "GYS_070");
|
||||
}
|
||||
|
||||
fTreeEntityList.add(fTreeEntityItem);
|
||||
}
|
||||
String jsonData = json.toString();
|
||||
log.info("打印json:" + jsonData);
|
||||
try {
|
||||
// 业务对象标识
|
||||
String formId = "ENG_BOM";
|
||||
// 调用接口
|
||||
String resultJson = client.save(formId, jsonData);
|
||||
|
||||
// 用于记录结果
|
||||
Gson gson = new Gson();
|
||||
// 对返回结果进行解析和校验
|
||||
RepoRet repoRet = gson.fromJson(resultJson, RepoRet.class);
|
||||
if (repoRet.getResult().getResponseStatus().isIsSuccess()) {
|
||||
log.debug("物料清单bom 保存成功===================>" + "图号:" + bomDetails1.getFNumber());
|
||||
String resultJson = new K3CloudApi().save("ENG_BOM", json.toString());
|
||||
// 直接用 Jackson 解析
|
||||
BOMUploadResult result = parseK3Response(resultJson);
|
||||
if (result.isSuccess()) {
|
||||
log.info("✅ BOM保存成功, 图号={}", bomDetails1.getFNumber());
|
||||
} else {
|
||||
log.error("物料清单bom 保存失败===================>" + "图号:" + bomDetails1.getFNumber());
|
||||
log.error("❌ BOM保存失败, 图号={}, 错误={}", bomDetails1.getFNumber(), result.getErrorMessage());
|
||||
}
|
||||
return result;
|
||||
} 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -527,5 +527,17 @@ public class EleMaterialsController extends BaseController {
|
||||
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("更新成功");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -270,7 +270,7 @@ public class ImMaterialController extends BaseController {
|
||||
|
||||
@XxlJob("updateMaterials")
|
||||
public Boolean updateMaterials() throws Exception {
|
||||
Date date = new Date();
|
||||
Date date = new Date();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
List<ImMaterial> imMaterials = updateJdMaterial(sdf.format(date));
|
||||
Boolean result = iImMaterialService.updateByFMid(imMaterials);
|
||||
@ -284,14 +284,14 @@ public class ImMaterialController extends BaseController {
|
||||
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");
|
||||
JsonArray filterString = new JsonArray();
|
||||
JsonObject filterObject = new JsonObject();
|
||||
/*JsonObject filterObject = new JsonObject();
|
||||
filterObject.addProperty("FieldName", "FForbidStatus"); // 使用传入的 fieldName
|
||||
filterObject.addProperty("Compare", "105");
|
||||
filterObject.addProperty("Value", "A");
|
||||
filterObject.addProperty("Left", "");
|
||||
filterObject.addProperty("Right", "");
|
||||
filterObject.addProperty("Logic", 0);
|
||||
filterString.add(filterObject);
|
||||
filterString.add(filterObject);*/
|
||||
JsonObject filterObject1 = new JsonObject();
|
||||
filterObject1.addProperty("FieldName", "FCreateDate"); // 使用传入的 fieldName
|
||||
filterObject1.addProperty("Compare", "93");
|
||||
@ -301,7 +301,7 @@ public class ImMaterialController extends BaseController {
|
||||
filterObject1.addProperty("Logic", 1);
|
||||
filterString.add(filterObject1);
|
||||
JsonObject filterObject2 = new JsonObject();
|
||||
filterObject2.addProperty("FieldName", "FCreateDate"); // 使用传入的 fieldName
|
||||
filterObject2.addProperty("FieldName", "FModifyDate"); // 使用传入的 fieldName
|
||||
filterObject2.addProperty("Compare", "93");
|
||||
filterObject2.addProperty("Value", date);
|
||||
filterObject2.addProperty("Left", "");
|
||||
@ -356,7 +356,7 @@ public class ImMaterialController extends BaseController {
|
||||
//请求参数,要求为json字符串
|
||||
JsonObject json = new JsonObject();
|
||||
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();
|
||||
|
||||
log.debug("构建查询条件...");
|
||||
@ -407,6 +407,7 @@ public class ImMaterialController extends BaseController {
|
||||
* 保存所有的物料编码
|
||||
* @return List<ImMaterial>
|
||||
*/
|
||||
@XxlJob("insertJDMaterial")
|
||||
@GetMapping("/insertJDMaterial")
|
||||
public List<ImMaterial> insertJDMaterial() throws Exception {
|
||||
List<ImMaterial> materialList = loadMaterial();
|
||||
|
||||
@ -476,28 +476,28 @@ public class KingdeeWorkCenterDataController extends BaseController {
|
||||
// 转入
|
||||
long transInQty = item.getLong("FTransInQty");
|
||||
//转出小于转入数量
|
||||
if (transOutQty<transInQty){
|
||||
// 转换为实体对象
|
||||
KingdeeWorkCenterDataBo data = new KingdeeWorkCenterDataBo();
|
||||
data.setWorkCenter(workCenter);
|
||||
data.setMoBillNo(item.getString("MoBillNo"));
|
||||
data.setMoOrderNo(item.getString("MoOrderNo"));
|
||||
data.setMaterialNumber(item.getString("FMaterialNumber"));
|
||||
data.setMaterialName(item.getString("FMaterialName"));
|
||||
data.setOperQty(item.getLong("FOperQty"));
|
||||
data.setTransInQty(transInQty);
|
||||
data.setTransOutQty(transOutQty);
|
||||
data.setOperNumber(item.getString("FOperNumber"));
|
||||
data.setProcessName(item.getString("FProcessName"));
|
||||
data.setOperPlanStartTime(item.getString("FOperPlanStartTime2"));
|
||||
data.setOperPlanFinishTime(planFinishTime);
|
||||
data.setDelayDays(item.getString("FDelayDays"));
|
||||
kingdeeWorkCenterDataVos.add(data);
|
||||
Boolean b = iKingdeeWorkCenterDataService.insertByBo(data);
|
||||
if (!b) {
|
||||
return R.fail("保存工段数据失败");
|
||||
if (transOutQty < transInQty) {
|
||||
// 转换为实体对象
|
||||
KingdeeWorkCenterDataBo data = new KingdeeWorkCenterDataBo();
|
||||
data.setWorkCenter(workCenter);
|
||||
data.setMoBillNo(item.getString("MoBillNo"));
|
||||
data.setMoOrderNo(item.getString("MoOrderNo"));
|
||||
data.setMaterialNumber(item.getString("FMaterialNumber"));
|
||||
data.setMaterialName(item.getString("FMaterialName"));
|
||||
data.setOperQty(item.getLong("FOperQty"));
|
||||
data.setTransInQty(transInQty);
|
||||
data.setTransOutQty(transOutQty);
|
||||
data.setOperNumber(item.getString("FOperNumber"));
|
||||
data.setProcessName(item.getString("FProcessName"));
|
||||
data.setOperPlanStartTime(item.getString("FOperPlanStartTime2"));
|
||||
data.setOperPlanFinishTime(planFinishTime);
|
||||
data.setDelayDays(item.getString("FDelayDays"));
|
||||
kingdeeWorkCenterDataVos.add(data);
|
||||
Boolean b = iKingdeeWorkCenterDataService.insertByBo(data);
|
||||
if (!b) {
|
||||
return R.fail("保存工段数据失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -677,7 +677,7 @@ public class KingdeeWorkCenterDataController extends BaseController {
|
||||
if (groupCodes.contains(materialCode)) {
|
||||
// 将物料添加到对应组的Map中
|
||||
groupMaterials.computeIfAbsent(groupType, k -> new HashMap<>())
|
||||
.put(materialCode, stock);
|
||||
.put(materialCode, stock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -706,9 +706,9 @@ public class KingdeeWorkCenterDataController extends BaseController {
|
||||
|
||||
// 查找对应的安全库存配置
|
||||
SafetyStock matchingSafetyStock = safetyStocks.stream()
|
||||
.filter(s -> s.getMaterialCode().equals(materialCode))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
.filter(s -> s.getMaterialCode().equals(materialCode))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (matchingSafetyStock == null) {
|
||||
log.warn("物料 {} 未找到对应的安全库存配置", materialCode);
|
||||
@ -744,14 +744,14 @@ public class KingdeeWorkCenterDataController extends BaseController {
|
||||
int result = baseMapper.insert(newStock);
|
||||
if (result > 0) {
|
||||
log.info("成功补充物料到数据库: 物料编码={}, 组={}, 使用模板物料={}",
|
||||
materialCode, groupType, template.getMaterialCode());
|
||||
materialCode, groupType, template.getMaterialCode());
|
||||
allStocks.add(newStock);
|
||||
} else {
|
||||
log.error("补充物料到数据库失败: 物料编码={}, 组={}", materialCode, groupType);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("补充物料到数据库失败: 物料编码={}, 组={}, 错误信息={}",
|
||||
materialCode, groupType, e.getMessage(), e);
|
||||
materialCode, groupType, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -763,6 +763,7 @@ public class KingdeeWorkCenterDataController extends BaseController {
|
||||
log.info("物料处理完成,最终物料总数: {}", allStocks.size());
|
||||
return allStocks;
|
||||
}
|
||||
|
||||
@Log(title = "金蝶安全库存数据", businessType = BusinessType.OTHER)
|
||||
@XxlJob("getKuCunTo40SB")
|
||||
public R<Void> getKuCunTo40SB() {
|
||||
@ -775,13 +776,13 @@ public class KingdeeWorkCenterDataController extends BaseController {
|
||||
String materialCode = "40SB/L";
|
||||
// 获取即时库存
|
||||
double inventoryQty = Optional.ofNullable(JdUtil.getKuCun(materialCode))
|
||||
.map(list ->list.stream()
|
||||
.map(list -> list.stream()
|
||||
.mapToDouble(JDInventoryDTO::getFBaseQty)
|
||||
.sum())
|
||||
.orElse(0.0);
|
||||
// 查询子项物料的未领料量
|
||||
double fNoPickedQty = Optional.ofNullable(JdUtil.getWeiLingliao(materialCode))
|
||||
.map(list ->list.stream()
|
||||
double fNoPickedQty = Optional.ofNullable(JdUtil.getWeiLingliao(materialCode))
|
||||
.map(list -> list.stream()
|
||||
.mapToDouble(JDProductionDTO::getFNoPickedQty)
|
||||
.sum())
|
||||
.orElse(0.0);
|
||||
@ -818,9 +819,8 @@ public class KingdeeWorkCenterDataController extends BaseController {
|
||||
.append("> **创建时间:** ").append(DateUtil.formatDateTime(new Date())).append("\n");
|
||||
|
||||
|
||||
|
||||
String part = markdownMsg.toString();
|
||||
wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId);
|
||||
String part = markdownMsg.toString();
|
||||
wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId);
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
@ -1011,10 +1011,10 @@ public class KingdeeWorkCenterDataController extends BaseController {
|
||||
for (PurchaseRequestExcelDTO allOrder : allOrders) {
|
||||
String productionOrderNo = allOrder.getFUCHNText();
|
||||
String deliveryDate = allOrder.getFArrivalDate();
|
||||
if (allOrder.getFCloseStatus().equals("A")){
|
||||
if (allOrder.getFCloseStatus().equals("A")) {
|
||||
allOrder.setFCloseStatus("未关闭");
|
||||
}
|
||||
if (allOrder.getFDocumentStatus().equals("C")){
|
||||
if (allOrder.getFDocumentStatus().equals("C")) {
|
||||
allOrder.setFDocumentStatus("已审核");
|
||||
}
|
||||
|
||||
@ -1048,6 +1048,7 @@ public class KingdeeWorkCenterDataController extends BaseController {
|
||||
log.info("过滤完成,剩余数量: {}", filteredOrders.size());
|
||||
return filteredOrders;
|
||||
}
|
||||
|
||||
@Log(title = "采购订单和采购申请单临期数据")
|
||||
@XxlJob("getPurchaseOrder2")
|
||||
@PostMapping("/getPurchaseOrder2")
|
||||
|
||||
@ -119,7 +119,7 @@ public class PcRigidChainController extends BaseController {
|
||||
}
|
||||
|
||||
|
||||
@SaCheckPermission("system:pcRigidChain:importVariableData')")
|
||||
@SaCheckPermission("system:pcRigidChain:importVariableData")
|
||||
@PostMapping("/importVariableData")
|
||||
public R<List<PcRigidChain>> importVariableData(@RequestParam("file") MultipartFile file) throws Exception {
|
||||
if (file == null || file.isEmpty()) {
|
||||
@ -131,8 +131,10 @@ public class PcRigidChainController extends BaseController {
|
||||
if (originalFilename == null || originalFilename.isEmpty()) {
|
||||
return R.fail("文件名不能为空");
|
||||
}
|
||||
String type = "";
|
||||
|
||||
log.info("开始处理文件: {}, 文件大小: {} bytes", originalFilename, fileBytes.length);
|
||||
|
||||
String type = "";
|
||||
if (originalFilename.contains("30D")) {
|
||||
type = "30D";
|
||||
} else if (originalFilename.contains("30S")) {
|
||||
@ -153,28 +155,45 @@ public class PcRigidChainController extends BaseController {
|
||||
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));
|
||||
List<PcRigidChain> pcRigidChainsToUpdate = null;
|
||||
for (ReadSheet readSheet : read.build().excelExecutor().sheetList()) {
|
||||
List<PcRigidChain> pcRigidChainsToUpdate = new ArrayList<>();
|
||||
|
||||
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);
|
||||
EasyExcel.read(new ByteArrayInputStream(fileBytes), PcRigidChainVo.class, excelListener)
|
||||
.excelType(ExcelTypeEnum.XLS)
|
||||
.sheet(readSheet.getSheetNo())
|
||||
.headRowNumber(3)
|
||||
.headRowNumber(4)
|
||||
.doRead();
|
||||
|
||||
List<PcRigidChainVo> list = excelListener.getExcelResult().getList();
|
||||
pcRigidChainsToUpdate = new ArrayList<>();
|
||||
log.info("工作表 {} 解析完成,共读取 {} 行数据", readSheet.getSheetName(), list.size());
|
||||
|
||||
// 批量查询数据库中的记录
|
||||
log.debug("开始查询数据库中类型为 {} 的记录", type);
|
||||
List<PcRigidChain> chains = iPcRigidChainService.selectPcRigidChainByType(type);
|
||||
log.info("数据库中共找到 {} 条类型为 {} 的记录", chains.size(), type);
|
||||
|
||||
Map<String, PcRigidChain> chainMap = chains.stream()
|
||||
.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) {
|
||||
processedCount++;
|
||||
Long vOne = pcRigidChainVO.getVOne();
|
||||
String sheetName = readSheet.getSheetName();
|
||||
String box = "";
|
||||
@ -187,40 +206,139 @@ public class PcRigidChainController extends BaseController {
|
||||
}
|
||||
|
||||
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) {
|
||||
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");
|
||||
dbChain.setJourney(vOne);
|
||||
dbChain.setTypeName(typeName);
|
||||
dbChain.setType(type);
|
||||
dbChain.setBox(box);
|
||||
dbChain.setAxialDirection(s);
|
||||
// dbChain.setUpdateBy(SecurityUtils.getUsername());
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pcRigidChainsToUpdate.isEmpty()) {
|
||||
|
||||
for (PcRigidChain pcRigidChain : pcRigidChainsToUpdate) {
|
||||
int i = pcRigidChainMapper.updateById(pcRigidChain);
|
||||
if (i > 0) {
|
||||
log.debug("物料:{}更新成功!!", pcRigidChain.getTypeName());
|
||||
log.info("物料: {} 已添加到更新列表", typeName);
|
||||
} else {
|
||||
log.debug("物料:{}更新失败!!", pcRigidChain.getTypeName());
|
||||
log.warn("未找到对应的数据库记录: {}", searchKey);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return R.fail("没有找到要更新的数据");
|
||||
}
|
||||
|
||||
log.info("工作表 {} 处理完成 - 处理记录数: {}, 匹配成功数: {}",
|
||||
readSheet.getSheetName(), processedCount, matchedCount);
|
||||
}
|
||||
|
||||
if (!pcRigidChainsToUpdate.isEmpty()) {
|
||||
log.info("开始批量更新数据库,共 {} 条记录", pcRigidChainsToUpdate.size());
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
|
||||
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);
|
||||
if (i > 0) {
|
||||
successCount++;
|
||||
log.info("物料:{} 更新成功!影响行数: {}", pcRigidChain.getTypeName(), i);
|
||||
} else {
|
||||
failCount++;
|
||||
log.warn("物料:{} 更新失败!影响行数: {}", pcRigidChain.getTypeName(), i);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("批量更新完成 - 成功: {} 条, 失败: {} 条", successCount, failCount);
|
||||
} else {
|
||||
log.warn("没有找到要更新的数据");
|
||||
return R.fail("没有找到要更新的数据");
|
||||
}
|
||||
|
||||
log.info("Excel导入处理完成,共处理 {} 条记录", pcRigidChainsToUpdate.size());
|
||||
return R.ok("导入成功", pcRigidChainsToUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,12 +3,14 @@ package com.ruoyi.system.controller;
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.ruoyi.common.excel.DefaultExcelListener;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.VersionComparator;
|
||||
import com.ruoyi.common.utils.file.SmbUtil;
|
||||
import com.ruoyi.common.poi.ExcelTemplateProc;
|
||||
import com.ruoyi.common.poi.DynamicDataMapping;
|
||||
@ -60,16 +62,13 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
@Slf4j
|
||||
@RequestMapping("/system/orderPro")
|
||||
public class ProcessOrderProController extends BaseController {
|
||||
|
||||
private final IProcessOrderProService iProcessOrderProService;
|
||||
@Autowired
|
||||
private final ProductionOrderServiceImpl productionOrderService;
|
||||
private final IMrpResultCheckService iMrpResultCheckService;
|
||||
private final IBomDetailsService iBomDetailsService;
|
||||
private final ProcessOrderProMapper processOrderProMapper;
|
||||
private final IImMaterialService imMaterialService;
|
||||
private final ISafetyStockService iSafetyStockService;
|
||||
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy年MM月dd日");
|
||||
/**
|
||||
* 查询项目令号列表
|
||||
*/
|
||||
@ -344,7 +343,8 @@ public class ProcessOrderProController extends BaseController {
|
||||
public List<OverdueProjectVo> getOverdueProjects() {
|
||||
return iProcessOrderProService.getOverdueProjects();
|
||||
}
|
||||
|
||||
@SaCheckPermission("system:orderPro:geMRPResults")
|
||||
@Log(title = "获取MRP复核结果", businessType = BusinessType.OTHER)
|
||||
@PostMapping("/getMRPResults/{id}")
|
||||
public R<List<MrpResultCheck>> geMRPResults(@PathVariable Long id) {
|
||||
return iMrpResultCheckService.getMRPResults(id);
|
||||
@ -371,7 +371,7 @@ public class ProcessOrderProController extends BaseController {
|
||||
|
||||
// 1. 读取第一个sheet的数据list - 使用POI直接读取以保留空格
|
||||
List<ProductionOrderVo> allDataList = readExcelWithPOI(excelName);
|
||||
|
||||
List<ProcessRoute> routeList = readExcelPOIRoute(excelName);
|
||||
// 2. 读取原始表数据
|
||||
List<BomDataVO> rawDataList = readRawDataTable(rawDataFile);
|
||||
|
||||
@ -391,7 +391,7 @@ public class ProcessOrderProController extends BaseController {
|
||||
if (materialCode != null) {
|
||||
String drawingNo = item.getDrawingNo();
|
||||
String drawingName = item.getDrawingName();
|
||||
if (drawingNo != null && drawingName != null) {
|
||||
if (drawingName != null) {
|
||||
ImMaterial material = imMaterialService.selectByCodeAndName(drawingNo, drawingName);
|
||||
if (material != null) {
|
||||
//判断是否是VMI物料
|
||||
@ -406,7 +406,7 @@ public class ProcessOrderProController extends BaseController {
|
||||
existingVmi.setQuantity(currentQuantity + itemQuantity);
|
||||
|
||||
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);
|
||||
found = true;
|
||||
break;
|
||||
@ -431,15 +431,44 @@ public class ProcessOrderProController extends BaseController {
|
||||
|| materialCode.startsWith("009001") || materialCode.startsWith("009081")
|
||||
|| (remark != null && remark.contains("外购"))) {
|
||||
// 过滤安全库存:如果属于安全库存,则进入工艺数据列表
|
||||
Boolean isSafeStock = iSafetyStockService.isSafeCode(materialCode);
|
||||
Boolean isSafeStock = iSafetyStockService.isSafeCode(materialCode.trim());
|
||||
if (isSafeStock) {
|
||||
// 属于安全库存,添加到工艺数据列表
|
||||
processDataList.add(item);
|
||||
continue; // 已分类,跳过后续检查
|
||||
} else {
|
||||
// 不属于安全库存,添加到电气外包列表
|
||||
ElecOutDataVO elecData = convertToElecOutDataVO(item);
|
||||
elecOutList.add(elecData);
|
||||
// 不属于安全库存,检查是否已存在相同的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);
|
||||
elecOutList.add(elecData);
|
||||
}
|
||||
continue; // 已分类,跳过后续检查
|
||||
}
|
||||
}
|
||||
@ -463,7 +492,7 @@ public class ProcessOrderProController extends BaseController {
|
||||
// 检查是否已存在相同的DrawingNo
|
||||
boolean found = false;
|
||||
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 itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0;
|
||||
@ -491,12 +520,12 @@ public class ProcessOrderProController extends BaseController {
|
||||
if (!found) {
|
||||
processDataList.add(item);
|
||||
}
|
||||
List<ProcessRouteExcelDTO> excelDTOList = iProcessOrderProService.getRouteAndBomDetail( processDataList,orderPro);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 使用Excel模板文件
|
||||
String templatePath = "EXCEL模板/生产及工艺计划模版.xlsx";
|
||||
String templatePath = "D:/java/excel-template/生产及工艺计划模版.xlsx";
|
||||
String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx";
|
||||
|
||||
// 准备模板数据
|
||||
@ -504,9 +533,29 @@ public class ProcessOrderProController extends BaseController {
|
||||
staticDataMap.put("productionOrderNo", orderPro.getProductionOrderNo());
|
||||
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<>();
|
||||
|
||||
@ -551,6 +600,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);
|
||||
@ -584,6 +638,44 @@ 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数据
|
||||
*/
|
||||
@ -850,7 +942,7 @@ public class ProcessOrderProController extends BaseController {
|
||||
elecData.setIndex(null); // ProductionOrder没有index字段
|
||||
elecData.setDrawingNo(item.getDrawingNo());
|
||||
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.setUnitWeight(item.getSingleWeight() != null ? BigDecimal.valueOf(item.getSingleWeight()) : null);
|
||||
elecData.setTotalWeight(item.getTotalWeight() != null ? BigDecimal.valueOf(item.getTotalWeight()) : null);
|
||||
@ -984,14 +1076,16 @@ public class ProcessOrderProController extends BaseController {
|
||||
}
|
||||
return mapList;
|
||||
}
|
||||
|
||||
private String formatDate(Date date) {
|
||||
return date == null ? "" : DATE_FORMAT.format(date);
|
||||
}
|
||||
/**
|
||||
* 转换工艺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<>();
|
||||
int index = 1;
|
||||
for (ProcessRouteVo item : routeDataList) {
|
||||
for (ProcessRouteExcelDTO item : routeDataList) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("index", index);
|
||||
map.put("routeDescription", item.getRouteDescription()); // 生产令号
|
||||
@ -1015,10 +1109,10 @@ public class ProcessOrderProController extends BaseController {
|
||||
map.put("unitQuantity", item.getUnitQuantity()); // 单台数量
|
||||
map.put("batchQuantity", item.getBatchQuantity()); // 本批数量
|
||||
map.put("firstBatchQuantity", item.getFirstBatchQuantity()); // 首批数量
|
||||
map.put("planStartTime", item.getPlanStartTime()); // 计划开始时间
|
||||
map.put("planEndTime", item.getPlanEndTime()); // 计划结束时间
|
||||
map.put("xuStartTime", item.getXuStartTime()); // 序开始时间
|
||||
map.put("xuEndTime", item.getXuEndTime()); // 序结束时间
|
||||
map.put("planStartTime", formatDate(item.getPlanStartTime()));
|
||||
map.put("planEndTime", formatDate(item.getPlanEndTime()));
|
||||
map.put("xuStartTime", formatDate(item.getXuStartTime()));
|
||||
map.put("xuEndTime", formatDate(item.getXuEndTime()));
|
||||
mapList.add(map);
|
||||
index++;
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@ import com.ruoyi.system.domain.vo.*;
|
||||
import com.ruoyi.system.jdmain.rouplan.Model;
|
||||
import com.ruoyi.system.mapper.BomDetailsMapper;
|
||||
import com.ruoyi.system.mapper.MaterialBomMapper;
|
||||
import com.ruoyi.system.mapper.ProcessOrderProMapper;
|
||||
import com.ruoyi.system.mapper.ProcessRouteMapper;
|
||||
import com.ruoyi.system.runner.JdUtil;
|
||||
import com.ruoyi.system.service.IBomDetailsService;
|
||||
@ -70,6 +71,7 @@ public class ProcessRouteController extends BaseController {
|
||||
@Autowired
|
||||
MaterialBomMapper materialBomMapper;
|
||||
private final IBomDetailsService iBomDetailsService;
|
||||
private final ProcessOrderProMapper proMapper;
|
||||
private Long generateUniqueParentId(Long originalId) {
|
||||
return originalId + 1000;
|
||||
}
|
||||
@ -393,7 +395,7 @@ public class ProcessRouteController extends BaseController {
|
||||
if (!route.isEmpty()){
|
||||
return R.fail("项目 "+productionOrderNo+"已导入过工艺 ,请先清空再上传");
|
||||
}
|
||||
if (iProcessRouteService.saveData(result.getList(), list)) {
|
||||
if (iProcessRouteService.saveData(list1, list)) {
|
||||
return R.ok("上传物料成功");
|
||||
} else {
|
||||
return R.fail("导入失败");
|
||||
@ -475,8 +477,9 @@ public class ProcessRouteController extends BaseController {
|
||||
public void generatePDFs(String rooteProdet, HttpServletResponse response) throws IOException {
|
||||
// 调用服务层方法生成 ZIP 文件并获取其路径
|
||||
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);
|
||||
if (!zipFile.exists()) {
|
||||
|
||||
@ -36,16 +36,19 @@ public class BomDetails extends BaseEntity {
|
||||
*/
|
||||
@JsonProperty("F_HBYT_BJMC")
|
||||
private String partdiagramName;
|
||||
|
||||
/**
|
||||
* 父级物料编码
|
||||
*/
|
||||
@JsonProperty("FMATERIALID.FNumber")
|
||||
private String fNumber;
|
||||
|
||||
/**
|
||||
* 父级物料名称
|
||||
*/
|
||||
@JsonProperty("FITEMNAME")
|
||||
private String fName;
|
||||
|
||||
/**
|
||||
* 子项物料单位
|
||||
*/
|
||||
@ -57,11 +60,13 @@ public class BomDetails extends BaseEntity {
|
||||
*/
|
||||
@JsonProperty("FMATERIALIDCHILD.FNumber")
|
||||
private String partNumber;
|
||||
|
||||
/**
|
||||
*子项物料名称
|
||||
*/
|
||||
@JsonProperty("FCHILDITEMNAME")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
*属性
|
||||
*/
|
||||
|
||||
@ -86,7 +86,8 @@ public class ImMaterial extends BaseEntity {
|
||||
/**
|
||||
* 搜索次数
|
||||
*/
|
||||
private Long searchCount;
|
||||
@JsonProperty("F_HBYT_PP")
|
||||
private String searchCount;
|
||||
/**
|
||||
* 金蝶修改时间当日
|
||||
*/
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -6,8 +6,6 @@ import java.util.Date;
|
||||
@Data
|
||||
public class ProcessRouteExcelDTO {
|
||||
|
||||
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
@ -35,7 +33,7 @@ public class ProcessRouteExcelDTO {
|
||||
/**
|
||||
* 单重KG
|
||||
*/
|
||||
private Double discWeight;
|
||||
private String discWeight;
|
||||
/**
|
||||
* 材料BOM物料编码
|
||||
*/
|
||||
@ -59,7 +57,7 @@ public class ProcessRouteExcelDTO {
|
||||
/**
|
||||
* 材料BOM用量
|
||||
*/
|
||||
private Double discUsage;
|
||||
private String discUsage;
|
||||
/**
|
||||
* 材料BOM单位
|
||||
*/
|
||||
@ -103,13 +101,13 @@ public class ProcessRouteExcelDTO {
|
||||
/**
|
||||
* 单台数量
|
||||
*/
|
||||
private Long unitQuantity;
|
||||
private String unitQuantity;
|
||||
|
||||
/**
|
||||
* 本批数量
|
||||
*/
|
||||
|
||||
private Long batchQuantity;
|
||||
private String batchQuantity;
|
||||
|
||||
/**
|
||||
* 首批数量
|
||||
|
||||
@ -73,7 +73,7 @@ public class EleMaterialsVo {
|
||||
/**
|
||||
* 物料值
|
||||
*/
|
||||
@ExcelProperty(value = "总工时")
|
||||
@ExcelProperty(value = "工时")
|
||||
private String materialValue;
|
||||
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ public class ElecOutDataVO {
|
||||
private String name;
|
||||
|
||||
/** 数量 */
|
||||
private Integer quantity;
|
||||
private Double quantity;
|
||||
|
||||
/** 材料 */
|
||||
private String material;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -52,7 +52,7 @@ public class PcRigidChainVo extends BaseEntity
|
||||
private String box;
|
||||
|
||||
/** 行程(mm) */
|
||||
@ExcelProperty( "{V1}")
|
||||
//@ExcelProperty( "{V1}")
|
||||
private Long journey;
|
||||
|
||||
/** 标记号 */
|
||||
|
||||
@ -1528,7 +1528,6 @@ public class JdUtil {
|
||||
needUpdateFields.add("FMATERIALID");
|
||||
needUpdateFields.add("FStandHourUnitId");
|
||||
|
||||
// 创建 NeedReturnFields 数组
|
||||
JsonArray needReturnFields = new JsonArray();
|
||||
needReturnFields.add("SubHeadEntity5_FEntryId");
|
||||
needReturnFields.add("FStdLaborProcessTime");
|
||||
|
||||
@ -58,7 +58,7 @@ public interface IProcessOrderProService {
|
||||
|
||||
List<ProcessRoute> selectProList(ProcessOrderProBo bo);
|
||||
|
||||
ProcessOrderProBo selectByProjectNumber(String routeDescription);
|
||||
ProcessOrderPro selectByProjectNumber(String routeDescription);
|
||||
|
||||
void batchUpdateProjectTimeRanges();
|
||||
List<ProcessOrderPro> selectByProjectNumbers(Set<String> routeDescSet);
|
||||
@ -78,5 +78,5 @@ public interface IProcessOrderProService {
|
||||
|
||||
List<OverdueProjectVo> getOverdueProjects();
|
||||
|
||||
List<ProcessRouteExcelDTO> getRouteAndBomDetail(List<ProductionOrderVo> processDataList,ProcessOrderPro orderPro);
|
||||
List<ProcessRouteExcelDTO> getRouteAndBomDetail(List<ProcessRoute> routlist,List<ProductionOrderVo> processDataList,ProcessOrderPro orderPro);
|
||||
}
|
||||
|
||||
@ -726,7 +726,7 @@ public class ImMaterialServiceImpl implements IImMaterialService {
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertJDMaterial(List<ImMaterial> materialList) {
|
||||
if (materialList.size()<0 || materialList.isEmpty()){
|
||||
if (materialList.isEmpty()){
|
||||
return false;
|
||||
}
|
||||
return baseMapper.insertBatch(materialList);
|
||||
|
||||
@ -37,11 +37,9 @@ import java.util.*;
|
||||
public class MrpResultCheckServiceImpl implements IMrpResultCheckService {
|
||||
|
||||
private final MrpResultCheckMapper baseMapper;
|
||||
private final FigureSaveMapper figureSaveMapper;
|
||||
private final ProcessOrderProMapper processOrderProMapper;
|
||||
private final IMaterialBomService iMaterialBomService;
|
||||
private final IProductionOrderService iProductionOrderService;
|
||||
private final IBomDetailsService iBomDetailsService;
|
||||
private final IProcessRouteService iProcessRouteService;
|
||||
/**
|
||||
* 查询MRP运算结果复查
|
||||
@ -281,7 +279,8 @@ public class MrpResultCheckServiceImpl implements IMrpResultCheckService {
|
||||
baseMapper.insert(vo);
|
||||
|
||||
}
|
||||
|
||||
processOrderPro.setBomStatus(4L);
|
||||
processOrderProMapper.updateById(processOrderPro);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package com.ruoyi.system.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import java.math.BigDecimal;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.lowagie.text.Rectangle;
|
||||
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.SmbUtils;
|
||||
import com.ruoyi.system.mapper.FigureSaveMapper;
|
||||
import com.ruoyi.system.mapper.MaterialBomMapper;
|
||||
import com.ruoyi.system.mapper.ProcessRouteMapper;
|
||||
import com.ruoyi.system.service.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
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.stereotype.Service;
|
||||
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(StringUtils.isNotBlank(bo.getUnit()), ProcessOrderPro::getUnit, bo.getUnit());
|
||||
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.getDrawingPath() != null, ProcessOrderPro::getDrawingPath, bo.getDrawingPath());
|
||||
//按照创建时间排序,最新的在顶端
|
||||
@ -245,18 +248,10 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ProcessOrderProBo selectByProjectNumber(String routeDescription) {
|
||||
public ProcessOrderPro selectByProjectNumber(String routeDescription) {
|
||||
LambdaQueryWrapper<ProcessOrderPro> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(ProcessOrderPro::getProductionOrderNo, routeDescription);
|
||||
ProcessOrderPro processOrderPro = baseMapper.selectOne(wrapper);
|
||||
ProcessOrderProBo processOrderProBo = new ProcessOrderProBo();
|
||||
|
||||
// 添加null检查
|
||||
if (processOrderPro != null) {
|
||||
BeanUtils.copyProperties(processOrderPro, processOrderProBo);
|
||||
}
|
||||
|
||||
return processOrderProBo;
|
||||
return baseMapper.selectOne(wrapper);
|
||||
}
|
||||
|
||||
|
||||
@ -288,7 +283,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
|
||||
|
||||
// 更新至计划模块中
|
||||
if (earliestStartTime != null && latestEndTime != null) {
|
||||
ProcessOrderProBo processOrderPro = selectByProjectNumber(projectNumber);
|
||||
ProcessOrderPro processOrderPro = selectByProjectNumber(projectNumber);
|
||||
|
||||
if (processOrderPro != null) {
|
||||
processOrderPro.setPlanStartTime(earliestStartTime);
|
||||
@ -359,7 +354,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
|
||||
pwProductionBill.setProduct(productInfos);
|
||||
|
||||
// 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()));
|
||||
}
|
||||
|
||||
private String callDrawingApi(PwProductionBill pwProductionBill,ProcessOrderProBo orderPro) {
|
||||
private String callDrawingApi(PwProductionBill pwProductionBill, ProcessOrderProBo orderPro) {
|
||||
try {
|
||||
String drawingDate = JSONObject.toJSONString(pwProductionBill);
|
||||
log.info("请求出图报文=====>{}", drawingDate);
|
||||
@ -557,7 +552,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
|
||||
// 判断完成条件processstate=4 表示完成
|
||||
if ("idle".equals(currentStatus) && processState == 4) {
|
||||
ProcessOrderPro processOrderPro = new ProcessOrderPro();
|
||||
BeanUtils.copyProperties(orderPro,processOrderPro);
|
||||
BeanUtils.copyProperties(orderPro, processOrderPro);
|
||||
|
||||
processOrderPro.setBomStatus(1L);//
|
||||
baseMapper.updateById(processOrderPro);
|
||||
@ -1072,7 +1067,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
|
||||
OverdueProjectVo projectVo = new OverdueProjectVo();
|
||||
|
||||
projectVo.setProjectCode(processOrderPro.getProductionName());
|
||||
// projectVo.setDesigner(processOrderPro.getProgramDesigner());
|
||||
// projectVo.setDesigner(processOrderPro.getProgramDesigner());
|
||||
projectVo.setStartDate(processOrderPro.getPlanStartTime().toString());
|
||||
projectVo.setPlanDate(processOrderPro.getPlanEndTime().toString());
|
||||
|
||||
@ -1106,6 +1101,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
|
||||
|
||||
/**
|
||||
* 递归删除目录及其内容
|
||||
*
|
||||
* @param directory 要删除的目录
|
||||
* @throws IOException 删除失败时抛出异常
|
||||
*/
|
||||
@ -1128,21 +1124,170 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将工艺部分 材料BOM部分 合并成ProcessRouteExcelDTO
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<ProcessRouteExcelDTO> getRouteAndBomDetail(List<ProductionOrderVo> processDataList,ProcessOrderPro orderPro) {
|
||||
String proRoot = orderPro.getProductionOrderNo();
|
||||
//工艺部分
|
||||
List<ProcessRoute> processRoutes = iProcessRouteService.selectByProjectNumber(proRoot);
|
||||
List<MaterialBom> materialBoms = materialBomService.selectByProCode(proRoot);
|
||||
for (ProductionOrderVo productionOrderVo : processDataList) {
|
||||
ProcessRouteExcelDTO processRouteExcelDTO = new ProcessRouteExcelDTO();
|
||||
public List<ProcessRouteExcelDTO> getRouteAndBomDetail(List<ProcessRoute> routlist,List<ProductionOrderVo> processDataList, ProcessOrderPro orderPro) {
|
||||
String proRoot = orderPro.getProductionOrderNo();
|
||||
|
||||
// 查出所有工艺路线和BOM
|
||||
List<ProcessRoute> allRoutes = iProcessRouteService.selectByProjectNumber(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<>();
|
||||
|
||||
// 规范化 key
|
||||
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)
|
||||
Map<String, List<MaterialBom>> bomMap = allBoms.stream()
|
||||
.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());
|
||||
if (maxSize == 0 && orderVo != null) maxSize = 1;
|
||||
|
||||
for (int i = 0; i < maxSize; i++) {
|
||||
ProcessRouteExcelDTO dto = new ProcessRouteExcelDTO();
|
||||
|
||||
// 补充名称/材质/单重字段
|
||||
dto.setMaterialCode(originalMaterialCode);
|
||||
dto.setMaterialName(originalMaterialName);
|
||||
dto.setMaterial(originalMaterial);
|
||||
dto.setDiscWeight(String.valueOf(originalUnitWeight));
|
||||
dto.setUnitQuantity(String.valueOf(unitQuantity));
|
||||
dto.setBatchQuantity(String.valueOf(batchQuantity));
|
||||
|
||||
// 订单数量信息
|
||||
if (orderVo != null) {
|
||||
dto.setRouteDescription(orderVo.getProductionOrderNo());
|
||||
dto.setUnitQuantity(String.valueOf(orderVo.getQuantity()));
|
||||
dto.setBatchQuantity(orderVo.getBatchQuantity());
|
||||
}
|
||||
|
||||
// 工艺部分
|
||||
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.setXuStartTime(route.getXuStartTime());
|
||||
dto.setXuEndTime(route.getXuEndTime());
|
||||
}
|
||||
|
||||
// BOM 部分
|
||||
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());
|
||||
|
||||
// 单位转换:如果单位为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);
|
||||
}
|
||||
} else {
|
||||
dto.setDiscUsage(quantity);
|
||||
}
|
||||
}
|
||||
resultList.add(dto);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -569,19 +569,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
|
||||
saveBomDetails(bomDetailsVos);
|
||||
List<ProcessRoute> routeArrayList = new ArrayList<>();
|
||||
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);
|
||||
//获取工艺中所有的时间 挑选出最早的时间和最晚的时间
|
||||
@ -622,8 +610,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
|
||||
for (ProcessRoute processRoute : processRoutes) {
|
||||
String materialCode = processRoute.getMaterialCode();
|
||||
Double kucun = inventoryCache.get(materialCode);
|
||||
boolean isDuplicateWelding = "组焊件".equals(processRoute.getMaterial())
|
||||
&& duplicateWeldingMaterials.contains(materialCode);
|
||||
boolean isDuplicateWelding = "组焊件".equals(processRoute.getMaterial()) && duplicateWeldingMaterials.contains(materialCode);
|
||||
|
||||
if (isDuplicateWelding && processedWeldingMaterials.contains(materialCode)) {
|
||||
continue;
|
||||
@ -663,7 +650,6 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
|
||||
defaultRoute.setProcessControl(null);
|
||||
defaultRoute.setActivityDuration(null);
|
||||
defaultRoute.setActivityUnit("分");
|
||||
defaultRoute.setFirstBatchQuantity(kucun);
|
||||
defaultRoute.setCreateTime(new Date());
|
||||
defaultRoute.setUpdateTime(new Date());
|
||||
routeArrayList.add(defaultRoute);
|
||||
@ -696,11 +682,14 @@ public class ProcessRouteServiceImpl implements IProcessRouteService {
|
||||
}
|
||||
} else {
|
||||
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.setCreateTime(new Date());
|
||||
processRoute.setUpdateTime(new Date());
|
||||
processRoute.setFirstBatchQuantity(processRoute.getFirstBatchQuantity());
|
||||
processRoute.setBatchQuantity(processRoute.getBatchQuantity());
|
||||
processRoute.setUnitQuantity(processRoute.getUnitQuantity());
|
||||
routeArrayList.add(processRoute);
|
||||
}
|
||||
|
||||
@ -158,9 +158,8 @@ public class SafetyStockServiceImpl implements ISafetyStockService {
|
||||
public Boolean isSafeCode(String materialCode) {
|
||||
LambdaQueryWrapper<SafetyStock> safetyStockLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
safetyStockLambdaQueryWrapper.eq(SafetyStock::getMaterialCode,materialCode);
|
||||
SafetyStock safetyStock = baseMapper.selectOne(safetyStockLambdaQueryWrapper);
|
||||
return safetyStock != null;
|
||||
|
||||
List<SafetyStock> safetyStocks = baseMapper.selectList(safetyStockLambdaQueryWrapper);
|
||||
return !safetyStocks.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -79,7 +79,7 @@ public class WorkProcedureServiceImpl implements IWorkProcedureService {
|
||||
parentTask.setParent(null);
|
||||
|
||||
// 获取工艺订单信息
|
||||
ProcessOrderProBo processOrderProBo = iProcessOrderProService.selectByProjectNumber(processRoute.getRouteDescription());
|
||||
ProcessOrderPro processOrderProBo = iProcessOrderProService.selectByProjectNumber(processRoute.getRouteDescription());
|
||||
|
||||
Date start = processOrderProBo.getPlanStartTime();
|
||||
Date end = processOrderProBo.getPlanEndTime();
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user