From 918935b13a102d9a379e4be28422c3b21a903d72 Mon Sep 17 00:00:00 2001 From: tzy <1042411602@qq.com> Date: Thu, 20 Mar 2025 08:41:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(system):=20=E6=96=B0=E5=A2=9E=E7=89=A9?= =?UTF-8?q?=E6=96=99BOM=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增物料BOM校验逻辑 - 添加货主信息更新功能 - 实现安全库存更新 - 优化物料导入导出功能 - 新增双单位支持 --- .../com/ruoyi/common/utils/WxRobotUtil.java | 16 +- .../controller/BomDetailsController.java | 181 ++++++++++++++++-- .../KingdeeWorkCenterDataController.java | 98 +++++++++- .../controller/WlStockDataController.java | 3 - .../controller/WorkProcedureController.java | 4 +- .../domain/dto/ProductctionPlanGatteDto.java | 1 + .../system/service/IWorkProcedureService.java | 2 + .../service/impl/EleMaterialsServiceImpl.java | 1 - .../service/impl/WlStockDataServiceImpl.java | 67 ++++++- .../impl/WorkProcedureServiceImpl.java | 100 ++++++++++ 10 files changed, 441 insertions(+), 32 deletions(-) diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxRobotUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxRobotUtil.java index 8a6aac7..9f9a7b4 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxRobotUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/WxRobotUtil.java @@ -94,20 +94,28 @@ public class WxRobotUtil { */ public void sendMarkdownMsgToWeChatGroup(String markdownMsg, String robotId) { + String messageContent = markdownMsg.toString(); + if (messageContent.length() > 4096) { + messageContent = messageContent.substring(0, 4096); // 截断到最大长度 + } HashMap paramMap = new HashMap<>(); HashMap markdownMap = new HashMap<>(); - markdownMap.put("content", markdownMsg); + markdownMap.put("content", messageContent); paramMap.put("msgtype", "markdown"); paramMap.put("markdown", markdownMap); String sendUrl = SEND_MESSAGE_URL + "?key=" + robotId; + log.info("发送URL: {}", sendUrl); + log.info("发送参数: {}", paramMap); + + ResponseEntity result = httpRequestUtil.doPost(sendUrl, paramMap); JSONObject dataObject = JSONObject.parseObject(JSONObject.toJSONString(result.getBody())); Integer errcode = Integer.valueOf(dataObject.get("errcode").toString()); if (errcode.equals(0)) { log.info("企业微信推送Markdown消息成功,时间:" + new Date()); } else { - log.error("企业微信推送Markdown消息失败,时间:" + new Date()); - } + log.error("企业微信推送Markdown消息失败,时间:" + new Date() + ",错误信息:" + dataObject.toJSONString()); + } } /** @@ -118,7 +126,7 @@ public class WxRobotUtil { * @param picUrl 图片链接 * @param robotId 机器人ID */ - public void sendNewsToWeChatGroup(String title, String description, String url, String picUrl, String robotId) { + public void sendNewsToWeChatGroup(String title, String description, String url, String picUrl, String robotId) { HashMap paramMap = new HashMap<>(); // 创建文章对象 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomDetailsController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomDetailsController.java index e4067e4..5e9e2e9 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomDetailsController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomDetailsController.java @@ -378,6 +378,7 @@ public class BomDetailsController extends BaseController { public R updateFBMaterial(@RequestBody List> bomDetailParams) { List bomDetailsList = new ArrayList<>(); Set processedMaterials = new HashSet<>(); // 用于跟踪已处理的物料编码 + List failedMaterials = new ArrayList<>(); // 用于跟踪处理失败的物料 // 遍历前端传来的数据 for (Map param : bomDetailParams) { @@ -393,18 +394,21 @@ public class BomDetailsController extends BaseController { for (BomDetails material : bomDetails) { // 只在第一次遇到该物料时新增父级物料 if (!processedMaterials.contains(material.getFNumber())) { - try { log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName()); + try { + log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName()); Double fbWorkTime = iProcessRouteService.getFaWorkTime(material); - JdUtil.loadChengPinMaterialPreservation(material,fbWorkTime); + JdUtil.loadChengPinMaterialPreservation(material, fbWorkTime); processedMaterials.add(material.getFNumber()); // 标记为已处理 } catch (Exception e) { log.error("新增父级物料失败: {}", e.getMessage()); + failedMaterials.add(material.getPartNumber()); } } // 获取工艺表中的非委外工时 Double fbWorkTime = iProcessRouteService.getFbWorkTime(material); - if (material.getPartNumber() != null && material.getName() != null&& material.getUnitWeight().equals("否")) { + if (material.getPartNumber() != null && material.getName() != null + && material.getUnitWeight().equals("否")) { String state = determineState(material); log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName()); @@ -414,29 +418,82 @@ public class BomDetailsController extends BaseController { log.info("新增物料成功 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName()); material.setUnitWeight("新增成功"); } else { - log.error("新增物料失败 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), - material.getName()); + log.error("新增物料失败 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName()); + failedMaterials.add(material.getPartNumber()); } // 更新物料状态 iBomDetailsService.updateByBo(BeanUtil.toBean(material, BomDetailsBo.class)); } catch (Exception e) { log.error("处理物料时发生异常: {}", e.getMessage()); + failedMaterials.add(material.getPartNumber()); } } else { log.error("物料信息不完整,无法新增物料"); + failedMaterials.add(material.getPartNumber()); } } - //保存物料之前进行BOM校验 - List selectBomList = JdUtil.getSelectBomList(fnumber); + + // 保存物料清单之前进行BOM校验 + if (!validateBOM(fnumber, bomDetails)) { + log.error("BOM校验失败,物料编码: {}", fnumber); + failedMaterials.add(fnumber); + continue; // 跳过保存 + } // 物料清单保存方法 FBloadBillOfMaterialsPreservation(bomDetails); bomDetailsList.addAll(bomDetails); } } + + // 返回处理结果 return R.ok("成功", bomDetailsList); } + // BOM 校验方法 + private boolean validateBOM(String fnumber, List bomDetails) { + List JDBomList = JdUtil.getSelectBomList(fnumber); + + // 1. 判断BOM是否为空 + if (JDBomList == null || JDBomList.isEmpty()) { + log.error("BOM为空,物料编码: {}", fnumber); + return false; // BOM校验失败 + } + + // 2. 检查子项数量是否一致 + if (JDBomList.size() != bomDetails.size()) { + log.error("BOM子项数量不一致,物料编码: {},金蝶子项数量: {},传入子项数量: {}", + fnumber, JDBomList.size(), bomDetails.size()); + return false; // BOM校验失败 + } + + // 3. 比较每个子项的内容 + for (int i = 0; i < JDBomList.size(); i++) { + BomDetails jdBomDetail = JDBomList.get(i); + BomDetails inputBomDetail = bomDetails.get(i); + + // 比较物料编码和名称 + if (!jdBomDetail.getFNumber().equals(inputBomDetail.getFNumber()) || + !jdBomDetail.getName().equals(inputBomDetail.getName())) { + log.error("BOM子项内容不一致,物料编码: {},金蝶物料: {},传入物料: {}", + fnumber, jdBomDetail.getFNumber(), inputBomDetail.getFNumber()); + return false; // BOM校验失败 + } + + // 比较分子和分母(假设有分子和分母字段) + if (!jdBomDetail.getDenominator().equals(inputBomDetail.getDenominator()) || + !jdBomDetail.getQuantity().equals(inputBomDetail.getQuantity())) { + log.error("BOM子项分子分母不一致,物料编码: {},金蝶分子: {}, 分母: {},传入分子: {}, 分母: {}", + fnumber, jdBomDetail.getDenominator(), jdBomDetail.getDenominator(), + inputBomDetail.getDenominator(), inputBomDetail.getDenominator()); + return false; // BOM校验失败 + } + } + + // 如果所有校验通过 + log.info("BOM校验通过,物料编码: {}", fnumber); + return true; // BOM校验成功 + } /* * 物料清单保存方法 @@ -671,10 +728,10 @@ public class BomDetailsController extends BaseController { fTreeEntityItem.addProperty("FNUMERATOR", details.getQuantity()); fTreeEntityItem.addProperty("FDENOMINATOR", details.getDenominator()); - //添加货主信息 查看这个bom中是否符合货主信息 + // 添加货主信息 查看这个bom中是否符合货主信息 String materialCode = details.getPartNumber(); Boolean vmiByCode = iMaterialTotalService.getVMIByCode(materialCode); - if (vmiByCode){ + if (vmiByCode) { fTreeEntityItem.addProperty("FOWNERTYPEID", "BD_Supplier"); JsonObject FOWNERID = new JsonObject(); fTreeEntityItem.add("FOWNERID", FOWNERID); @@ -1318,7 +1375,7 @@ public class BomDetailsController extends BaseController { // 添加Model字段 model.addProperty("FMATERIALID", 0); - if(!(bomDetails1.getDanzhong() ==null)){ + if (!(bomDetails1.getDanzhong() == null)) { model.addProperty("F_HBYT_DZ", bomDetails1.getDanzhong()); } model.addProperty("FSpecification", bomDetails1.getRemarks()); @@ -1366,8 +1423,23 @@ public class BomDetailsController extends BaseController { // 创建FBaseUnitId对象,并加入SubHeadEntity JsonObject fBaseUnitId = new JsonObject(); - fBaseUnitId.addProperty("FNumber", "jian"); subHeadEntity.add("FBaseUnitId", fBaseUnitId); + if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) { + if (bomDetails1.getWareHouse() != null) { + if (bomDetails1.getWareHouse().equals("KG")) { + fBaseUnitId.addProperty("FNumber", "004"); + } + if (bomDetails1.getWareHouse().equals("根")) { + fBaseUnitId.addProperty("FNumber", "003"); + } + if (bomDetails1.getWareHouse().equals("mm")) { + fBaseUnitId.addProperty("FNumber", "005"); + } + } + } else { + fBaseUnitId.addProperty("FNumber", "jian"); + } + if (states.equals("1")) { subHeadEntity.addProperty("FIsPurchase", true); subHeadEntity.addProperty("FIsSale", true); @@ -1385,8 +1457,24 @@ public class BomDetailsController extends BaseController { JsonObject subHeadEntity1 = new JsonObject(); model.add("SubHeadEntity1", subHeadEntity1); JsonObject fStoreUnitId = new JsonObject(); - fStoreUnitId.addProperty("FNumber", "jian"); subHeadEntity1.add("FStoreUnitID", fStoreUnitId); + // 如果是原材料的话且 + if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) { + if (bomDetails1.getWareHouse() != null) { + if (bomDetails1.getWareHouse().equals("KG")) { + fStoreUnitId.addProperty("FNumber", "004"); + } + if (bomDetails1.getWareHouse().equals("根")) { + fStoreUnitId.addProperty("FNumber", "003"); + } + if (bomDetails1.getWareHouse().equals("mm")) { + fStoreUnitId.addProperty("FNumber", "005"); + } + } + } else { + fStoreUnitId.addProperty("FNumber", "jian"); + } + subHeadEntity1.addProperty("FUnitConvertDir", "1"); // 创建FStockId对象,并加入SubHeadEntity1 @@ -1407,6 +1495,21 @@ public class BomDetailsController extends BaseController { // 创建FPurchaseUnitId对象,并加入SubHeadEntity1 JsonObject fPurchaseUnitId = new JsonObject(); fPurchaseUnitId.addProperty("FNumber", "jian"); + if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) { + if (bomDetails1.getWareHouse() != null) { + if (bomDetails1.getWareHouse().equals("KG")) { + fPurchaseUnitId.addProperty("FNumber", "004"); + } + if (bomDetails1.getWareHouse().equals("根")) { + fPurchaseUnitId.addProperty("FNumber", "003"); + } + if (bomDetails1.getWareHouse().equals("mm")) { + fPurchaseUnitId.addProperty("FNumber", "005"); + } + } + } else { + fPurchaseUnitId.addProperty("FNumber", "jian"); + } subHeadEntity1.add("FPurchaseUnitId", fPurchaseUnitId); // 创建SubHeadEntity3对象,并加入Model @@ -1416,6 +1519,22 @@ public class BomDetailsController extends BaseController { // 创建FPurchasePriceUnitId对象,并加入SubHeadEntity3 JsonObject fPurchasePriceUnitId = new JsonObject(); fPurchasePriceUnitId.addProperty("FNumber", "jian"); + if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) { + if (bomDetails1.getWareHouse() != null) { + if (bomDetails1.getWareHouse().equals("KG")) { + fPurchasePriceUnitId.addProperty("FNumber", "004"); + } + if (bomDetails1.getWareHouse().equals("根")) { + fPurchasePriceUnitId.addProperty("FNumber", "003"); + } + if (bomDetails1.getWareHouse().equals("mm")) { + fPurchasePriceUnitId.addProperty("FNumber", "005"); + } + } + } else { + fPurchasePriceUnitId.addProperty("FNumber", "jian"); + } + subHeadEntity3.add("FPurchasePriceUnitId", fPurchasePriceUnitId); subHeadEntity3.addProperty("FIsQuota", false); @@ -1450,6 +1569,21 @@ public class BomDetailsController extends BaseController { // 创建FProduceUnitId对象,并加入SubHeadEntity5 JsonObject fProduceUnitId = new JsonObject(); fProduceUnitId.addProperty("FNumber", "jian"); + if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) { + if (bomDetails1.getWareHouse() != null) { + if (bomDetails1.getWareHouse().equals("KG")) { + fProduceUnitId.addProperty("FNumber", "004"); + } + if (bomDetails1.getWareHouse().equals("根")) { + fProduceUnitId.addProperty("FNumber", "003"); + } + if (bomDetails1.getWareHouse().equals("mm")) { + fProduceUnitId.addProperty("FNumber", "005"); + } + } + } else { + fProduceUnitId.addProperty("FNumber", "jian"); + } subHeadEntity5.add("FProduceUnitId", fProduceUnitId); // 实际作工时,并加入SubHeadEntity5 @@ -1461,7 +1595,24 @@ public class BomDetailsController extends BaseController { // 创建FBOMUnitId对象,并加入SubHeadEntity5 JsonObject fBOMUnitId = new JsonObject(); fBOMUnitId.addProperty("FNumber", "jian"); + if (bomDetails1.getPartNumber().startsWith("015") || bomDetails1.getName().contains("磨光棒")) { + if (bomDetails1.getWareHouse() != null) { + if (bomDetails1.getWareHouse().equals("KG")) { + fBOMUnitId.addProperty("FNumber", "004"); + } + if (bomDetails1.getWareHouse().equals("根")) { + fBOMUnitId.addProperty("FNumber", "003"); + } + if (bomDetails1.getWareHouse().equals("mm")) { + fBOMUnitId.addProperty("FNumber", "005"); + } + } + + } else { + fBOMUnitId.addProperty("FNumber", "jian"); + } subHeadEntity5.add("FBOMUnitId", fBOMUnitId); + if (states.equals("1")) { subHeadEntity5.addProperty("FIsMainPrd", false); } else { @@ -1880,11 +2031,7 @@ public class BomDetailsController extends BaseController { break; } subHeadEntity5.add("FBOMUnitId", fBOMUnitId); - if (states.equals("1")) { - subHeadEntity5.addProperty("FIsMainPrd", false); - } else { - subHeadEntity5.addProperty("FIsMainPrd", true); - } + subHeadEntity5.addProperty("FIsMainPrd", !states.equals("1")); subHeadEntity5.addProperty("FIssueType", "1"); // 创建FPickStockId对象,并加入SubHeadEntity5 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/KingdeeWorkCenterDataController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/KingdeeWorkCenterDataController.java index ab6f2d0..8289332 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/KingdeeWorkCenterDataController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/KingdeeWorkCenterDataController.java @@ -21,10 +21,17 @@ import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.google.gson.JsonObject; import com.kingdee.bos.webapi.sdk.K3CloudApi; import com.ruoyi.common.utils.HttpRequestUtil; import com.ruoyi.common.utils.WxRobotUtil; +import com.ruoyi.system.domain.SafetyStock; +import com.ruoyi.system.domain.WlStockData; +import com.ruoyi.system.domain.vo.SafetyStockVo; +import com.ruoyi.system.domain.vo.WlStockDataVo; +import com.ruoyi.system.mapper.SafetyStockMapper; +import com.ruoyi.system.mapper.WlStockDataMapper; import com.xxl.job.core.handler.annotation.XxlJob; import lombok.RequiredArgsConstructor; @@ -70,7 +77,7 @@ public class KingdeeWorkCenterDataController extends BaseController { private final IKingdeeWorkCenterDataService iKingdeeWorkCenterDataService; private final HttpRequestUtil httpRequestUtil; private static final Logger log = LoggerFactory.getLogger(KingdeeWorkCenterDataController.class); - + private final WlStockDataMapper baseMapper;; /** * 查询金蝶工段数据列表 */ @@ -263,7 +270,12 @@ public class KingdeeWorkCenterDataController extends BaseController { "> 数量信息:计划1.00,已转入1.00,已转出0.00\n\n" + "请相关部门负责人关注并及时处理!"; - wxRobotUtil.sendMarkdownMsgToWeChatGroup(markdownMsg, robotId); + String messageContent = markdownMsg; + int maxLength = 4096; + for (int i = 0; i < messageContent.length(); i += maxLength) { + String part = messageContent.substring(i, Math.min(i + maxLength, messageContent.length())); + wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId); + } return R.ok(); } @@ -336,7 +348,12 @@ public class KingdeeWorkCenterDataController extends BaseController { // 添加结束语 markdownMsg.append("请相关部门负责人关注并及时处理!"); // 发送消息 - wxRobotUtil.sendMarkdownMsgToWeChatGroup(markdownMsg.toString(), robotId); + String messageContent = markdownMsg.toString(); + int maxLength = 4096; + for (int i = 0; i < messageContent.length(); i += maxLength) { + String part = messageContent.substring(i, Math.min(i + maxLength, messageContent.length())); + wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId); + } return R.ok(); @@ -556,5 +573,80 @@ public class KingdeeWorkCenterDataController extends BaseController { return R.fail("发送工段数据失败:" + e.getMessage()); } } + @SaCheckPermission("system:workCenterData:getKuCun") + @Log(title = "金蝶工段数据延期数据", businessType = BusinessType.DELETE) + @PostMapping("/getKuCun") + public R getKuCun() { + + String robotId = "0d2390e0-3e74-49fc-bd02-900b86bf0f55"; + StringBuilder markdownMsg = new StringBuilder(); + + // 获取今天的日期 + Date today = new Date(); + Date sixAM = DateUtil.parse(DateUtil.format(today, "yyyy-MM-dd") + " 06:00:00"); + + // 创建查询条件 + LambdaQueryWrapper safetyStockLambdaQueryWrapper = new LambdaQueryWrapper<>(); + // 获取时间在今天6点以后的数据 + safetyStockLambdaQueryWrapper.ge(WlStockData::getCreateTime, sixAM); + + List safetyStocks = baseMapper.selectList(safetyStockLambdaQueryWrapper); + try { + if (CollUtil.isEmpty(safetyStocks)) { + markdownMsg.append("## 🚀 安全库存提醒\n\n") + .append("今日暂无安全库存预警数据。"); + } else { + markdownMsg.append("## 🚀 安全库存提醒\n\n") + .append("以下是今日的安全库存预警数据:\n\n"); + + // 只显示前三个安全库存数据 + int count = Math.min(3, safetyStocks.size()); + for (int i = 0; i < count; i++) { + WlStockData safetyStock = safetyStocks.get(i); + markdownMsg.append("### 物料信息\n") + .append("#### 物料编号: **").append(safetyStock.getMaterialCode()).append("**\n") + .append("> **物料名称:** ").append(safetyStock.getMaterialName()).append("\n") + .append("> **可用库存:** ").append(String.format("%.2f", safetyStock.getAvailableStock())).append("\n") + .append("> **当前库存:** ").append(String.format("%.2f", safetyStock.getCurrentStock())).append("\n") + .append("> **最大库存:** ").append(String.format("%.2f", safetyStock.getMaxsafetyStock())).append("\n") + .append("> **创建时间:** ").append(DateUtil.formatDateTime(safetyStock.getCreateTime())).append("\n") + .append("---\n"); // 添加分隔线 + } + + // 添加总数汇总 + markdownMsg.append("### 总数汇总\n") + .append("> 今日安全库存预警数据总数: **").append(safetyStocks.size()).append("**\n"); + } + + // 生成Excel文件 + String fileName = String.format("%s安全预警数据_%s.xlsx","企标", DateUtil.format(new Date(), "yyyyMMddHHmmss")); + String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName; + + // 使用EasyExcel写入数据 + EasyExcel.write(filePath, WlStockDataVo.class) + .sheet("工段数据") + .doWrite(BeanUtil.copyToList(safetyStocks, WlStockDataVo.class)); + + // 发送Excel文件 + File excelFile = new File(filePath); + wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId); + + // 删除临时文件 + FileUtils.deleteQuietly(excelFile); + markdownMsg.append("\n详细数据请查看发送的Excel文件!"); + String messageContent = markdownMsg.toString(); + int maxLength = 1000; + for (int i = 0; i < messageContent.length(); i += maxLength) { + String part = messageContent.substring(i, Math.min(i + maxLength, messageContent.length())); + wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId); + } + return R.ok(); + } catch (Exception e) { + markdownMsg.append("- ").append("安全库存").append(" (获取失败: ").append(e.getMessage()).append(")\n"); + return R.fail("发送安全库存数据失败:" + e.getMessage()); + } + + } + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/WlStockDataController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/WlStockDataController.java index 3041ea2..9e4f8ad 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/WlStockDataController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/WlStockDataController.java @@ -101,7 +101,6 @@ public class WlStockDataController extends BaseController { /** * 删除安全库存单据 - * * @param ids 主键串 */ @SaCheckPermission("system:stockData:remove") @@ -114,8 +113,6 @@ public class WlStockDataController extends BaseController { /** * 生成安全库存单据 - * - * @return */ @SaCheckPermission("system:stockData:generateDoc") @Log(title = "安全库存单据", businessType = BusinessType.OTHER) diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/WorkProcedureController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/WorkProcedureController.java index a5faf4e..4489da8 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/WorkProcedureController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/WorkProcedureController.java @@ -45,7 +45,7 @@ import java.util.Map; /** * 工序任务 * - * @author ruoyi + * @author tzy * @date 2024-06-27 */ @Validated @@ -54,7 +54,7 @@ import java.util.Map; @RequestMapping("/system/procedure") public class WorkProcedureController extends BaseController { - private static final Logger log = LoggerFactory.getLogger(KingdeeWorkCenterDataController.class); + private static final Logger log = LoggerFactory.getLogger(WorkProcedureController.class); private final IWorkProcedureService iWorkProcedureService; private final IKingdeeWorkCenterDataService iKingdeeWorkCenterDataService; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProductctionPlanGatteDto.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProductctionPlanGatteDto.java index bd9064e..e21dff0 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProductctionPlanGatteDto.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProductctionPlanGatteDto.java @@ -14,6 +14,7 @@ public class ProductctionPlanGatteDto { private String text; private String start_date; private String end_date; + //天数 private Long duration; private Integer type; private Boolean open; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IWorkProcedureService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IWorkProcedureService.java index dee13d1..6e9c853 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IWorkProcedureService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IWorkProcedureService.java @@ -50,4 +50,6 @@ public interface IWorkProcedureService { Boolean deleteWithValidByIds(Collection ids, Boolean isValid); List getGongXuTasks(String text); + + List getAllTasks1(); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EleMaterialsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EleMaterialsServiceImpl.java index 8b1ca3d..c651c8d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EleMaterialsServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EleMaterialsServiceImpl.java @@ -145,7 +145,6 @@ public class EleMaterialsServiceImpl implements IEleMaterialsService { @Override public Boolean updateByBo(EleMaterialsBo bo) { EleMaterials update = BeanUtil.toBean(bo, EleMaterials.class); - validEntityBeforeSave(update); return baseMapper.updateById(update) > 0; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WlStockDataServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WlStockDataServiceImpl.java index 439deae..fc7b089 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WlStockDataServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WlStockDataServiceImpl.java @@ -25,6 +25,7 @@ import com.ruoyi.system.mapper.SafetyStockMapper; import com.ruoyi.system.mapper.WlStockDataMapper; import com.ruoyi.system.runner.JdUtil; import com.ruoyi.system.service.IWlStockDataService; +import com.xxl.job.core.handler.annotation.XxlJob; import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -229,7 +230,69 @@ public class WlStockDataServiceImpl implements IWlStockDataService { } } } + @XxlJob("generateDoc2") + public List generateDoc2() { + List safetyStocks = safetyStockMapper.selectList(); + if (CollectionUtils.isEmpty(safetyStocks)) { + logger.warn("没有找到安全库存数据"); + logMessages("没有找到安全库存数据"); + return Collections.emptyList(); + } + // 使用固定大小的线程池而不是CachedThreadPool,避免创建过多线程 + ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + List wlStockDataList = Collections.synchronizedList(new ArrayList<>()); + + try { + // 创建所有任务的Future列表 + List> futures = safetyStocks.stream() + .map(safetyStock -> CompletableFuture + .supplyAsync(() -> processWithRetry(safetyStock), executor) + .thenAccept(wlStockData -> { + if (wlStockData != null) { + wlStockDataList.add(wlStockData); + } + }) + .exceptionally(e -> { + logger.error("处理安全库存数据失败: {}", safetyStock.getMaterialCode(), e); + logMessages("处理安全库存数据失败: " + safetyStock.getMaterialCode()); + return null; + })) + .collect(Collectors.toList()); + + // 等待所有任务完成 + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .get(5, TimeUnit.MINUTES); // 设置整体超时时间 + + // 批量保存数据 + if (!wlStockDataList.isEmpty()) { + boolean success = baseMapper.insertBatch(wlStockDataList); + logger.info("批量插入{}条数据: {}", wlStockDataList.size(), success); + logMessages("批量插入" + wlStockDataList.size() + "条数据成功"); + } + + return wlStockDataList; + + } catch (TimeoutException e) { + logger.error("生成文档操作超时", e); + logMessages("生成单据操作超时"); + throw new ServiceException("操作超时,请稍后重试"); + } catch (Exception e) { + logger.error("生成文档时发生错误", e); + logMessages("生成单据发生错误: " + e.getMessage()); + throw new ServiceException("生成文档失败:" + e.getMessage()); + } finally { + executor.shutdown(); + try { + if (!executor.awaitTermination(30, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } private WlStockData processWithRetry(SafetyStock safetyStock) { int retryCount = 0; while (retryCount < MAX_RETRIES) { @@ -356,11 +419,11 @@ public class WlStockDataServiceImpl implements IWlStockDataService { wlStockData.setMaxsafetyStock(BigDecimal.valueOf(maxSafetyStock)); wlStockData.setSecAvbqty(BigDecimal.valueOf(fSecAVBQty)); - wlStockData.setDocumentType(String.format("物料编码:%s||可用库存:%.2f||库存量:%.2f||生产订单:%.2f||" + + /* wlStockData.setDocumentType(String.format("物料编码:%s||可用库存:%.2f||库存量:%.2f||生产订单:%.2f||" + "采购订单:%.2f||预留量:%.2f||最大库存:%.2f||最低库存:%.2f", safetyStock.getMaterialCode(), availableStock, fSecAVBQty, productionQty, purchaseQty, fSecQty, maxSafetyStock, minSafetyStock)); - +*/ return wlStockData; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkProcedureServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkProcedureServiceImpl.java index c530375..c832efb 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkProcedureServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkProcedureServiceImpl.java @@ -1,11 +1,17 @@ package com.ruoyi.system.service.impl; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.gson.JsonObject; +import com.kingdee.bos.webapi.sdk.K3CloudApi; import com.ruoyi.common.core.domain.PageQuery; +import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.ProductionPlan; @@ -22,6 +28,7 @@ import org.springframework.stereotype.Service; import java.text.SimpleDateFormat; import java.time.LocalDate; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; @@ -130,6 +137,99 @@ public class WorkProcedureServiceImpl implements IWorkProcedureService { return tasks; } + public List getAllTasks1() { + try { + K3CloudApi client = new K3CloudApi(); + JsonObject parameter = new JsonObject(); + parameter.addProperty("FWorkCenterName", "机一工段"); + Object[] parameters = new Object[] { parameter.toString() }; + String execute = client.execute( + "Ljint.Kingdee.YiTe.KanBan.WebApi.ProduceWebApi.ExecuteService,Ljint.Kingdee.YiTe.KanBan.WebApi", + parameters); + + // 解析响应 + JSONObject response = JSONObject.parseObject(execute); + if (!"true".equals(response.getString("IsSuccess"))) { + String errorMsg = response.getString("Message"); + return null; + } + + // 获取明天的日期字符串 (格式: yyyy-MM-dd) + String tomorrow = DateUtil.format(DateUtil.tomorrow().toLocalDateTime().plusDays(1), "yyyy-MM-dd"); + + // 获取数据数组 + JSONArray dataArray = response.getJSONArray("data"); + if (dataArray == null || dataArray.isEmpty()) { + return null; + } + + List tasks = new ArrayList<>(); + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + for (int i = 0; i < dataArray.size(); i++) { + JSONArray queryList = dataArray.getJSONObject(i).getJSONArray("QueryList"); + for (int j = 0; j < queryList.size(); j++) { + JSONObject item = queryList.getJSONObject(j); + + // 获取计划结束时间并转换为日期格式进行比较 + String planFinishTime = item.getString("FOperPlanFinishTime2"); + if (org.springframework.util.StringUtils.hasText(planFinishTime)) { + // 提取日期部分进行比较 (去掉时间部分) + String finishDate = planFinishTime.split(" ")[0]; + // 只处理明天结束的工单 + if (tomorrow.equals(finishDate)) { + // 转换为 ProductctionPlanGatteDto 对象 + ProductctionPlanGatteDto task = new ProductctionPlanGatteDto(); + task.setId(item.getLong("Id")); // 假设有 Id 字段 + task.setText(item.getString("MoOrderNo")); + task.setToolTipsTxt(item.getString("FProcessName")); + task.setType(1); + LocalDate startDate = item.getDate("FOperPlanStartTime2").toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + LocalDate endDate = item.getDate("FOperPlanFinishTime2").toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + task.setStart_date(startDate.toString()); + task.setEnd_date(endDate.toString()); + + long duration = ChronoUnit.DAYS.between(startDate, endDate); + task.setDuration(duration); + + task.setOpen(true); + task.setProgress(1L); + task.setStatus("yellow"); + task.setParent(null); // 父任务没有parent + + tasks.add(task); + + // 处理子任务 + JSONArray subTasksArray = item.getJSONArray("SubTasks"); + if (subTasksArray != null) { + for (int k = 0; k < subTasksArray.size(); k++) { + JSONObject subTaskItem = subTasksArray.getJSONObject(k); + ProductctionPlanGatteDto subTask = new ProductctionPlanGatteDto(); + subTask.setId(subTaskItem.getLong("SubTaskId")); + subTask.setText(subTaskItem.getString("FProcessName")); + subTask.setToolTipsTxt(subTaskItem.getString("SubTaskProcessName")); + subTask.setStart_date(subTaskItem.getString("FOperPlanStartTime2")); + subTask.setEnd_date(subTaskItem.getString("FOperPlanFinishTime2")); + subTask.setDuration(subTaskItem.getLong("1")); + subTask.setOpen(true); + subTask.setProgress(1L); + subTask.setStatus("yellow"); + subTask.setParent(task.getId()); // 设置父任务ID + + tasks.add(subTask); + } + } + } + } + } + } + + return tasks; + + } catch (Exception e) { + return null; + } + } /** * 查询工序任务