From 5a3739b2bc972d1cceb83a073398b9c28d8b1a35 Mon Sep 17 00:00:00 2001 From: tzy Date: Wed, 5 Nov 2025 16:43:57 +0800 Subject: [PATCH] =?UTF-8?q?*=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1=E6=8E=A8?= =?UTF-8?q?=E9=80=81=20*bom=20Jiaoyan=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-common/pom.xml | 6 + .../monitor/admin/config/SecurityConfig.java | 2 + ruoyi-system/pom.xml | 2 +- .../controller/BomDetailsController.java | 147 ++-- .../controller/BomVariableController.java | 2 +- .../controller/ImMaterialController.java | 2 +- .../KingdeeWorkCenterDataController.java | 629 ++++++++++++++-- .../system/controller/PartCostController.java | 119 +++ .../controller/PcRigidChainController.java | 83 +- .../controller/ProcessOrderProController.java | 16 +- .../controller/ProcessRouteController.java | 8 +- .../com/ruoyi/system/domain/BomDetails.java | 6 +- .../com/ruoyi/system/domain/PartCost.java | 72 ++ .../ruoyi/system/domain/bo/BomDetailsBo.java | 4 + .../ruoyi/system/domain/bo/PartCostBo.java | 88 +++ .../com/ruoyi/system/domain/dto/BOMItem.java | 10 + .../system/domain/dto}/BOMUploadResult.java | 2 +- .../domain/dto/ConstructionDelayDTO.java | 48 ++ .../system/domain/dto/InspectionSheetDTO.java | 64 ++ .../system/domain/dto/OperationPlannDTO.java | 18 + .../domain/dto/ProcessInspectionDTO.java | 51 ++ .../system/domain/dto/ProcessReportDTO.java | 60 ++ .../system/domain/dto/ProcessRouteXuDTO.java | 5 + .../domain/dto/ProcessTransferFormDTO.java | 77 ++ .../system/domain/dto/ProductionOrderDTO.java | 70 ++ .../domain/dto/PurchaseOrderExcelDTO.java | 5 + .../domain/dto/PurchaseRequestExcelDTO.java | 8 +- .../ruoyi/system/domain/vo/BomDetailsVo.java | 5 +- .../domain/vo/ElectricalMaterialBomVO.java | 4 +- .../ruoyi/system/domain/vo/PartCostVo.java | 79 ++ .../ruoyi/system/mapper/PartCostMapper.java | 15 + .../java/com/ruoyi/system/runner/JdUtil.java | 706 ++++++++++++++++-- .../com/ruoyi/system/runner/PDFGenerator.java | 168 ++++- .../system/runner/updatePcessPlanConver.java | 2 - .../system/service/IPartCostService.java | 50 ++ .../system/service/IProcessRouteService.java | 8 +- .../service/impl/BomDetailsServiceImpl.java | 6 +- .../service/impl/ImMaterialServiceImpl.java | 26 +- .../service/impl/MaterialBomServiceImpl.java | 2 +- .../service/impl/PartCostServiceImpl.java | 166 ++++ .../impl/ProcessOrderProServiceImpl.java | 6 +- .../service/impl/ProcessRouteServiceImpl.java | 127 +++- .../resources/EXCEL模板/工序汇报未入库.xlsx | Bin 0 -> 10474 bytes .../resources/EXCEL模板/工序转移数据.xlsx | Bin 0 -> 9968 bytes .../EXCEL模板/生产开工未领料模板.xlsx | Bin 0 -> 10745 bytes .../resources/EXCEL模板/采购订单模板1.xlsx | Bin 11402 -> 11478 bytes .../mapper/system/BomDetailsMapper.xml | 1 + .../mapper/system/PartCostMapper.xml | 24 + .../mapper/system/ProcessOrderProMapper.xml | 2 +- 49 files changed, 2671 insertions(+), 330 deletions(-) create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controller/PartCostController.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/PartCost.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/PartCostBo.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/BOMItem.java rename {ruoyi-common/src/main/java/com/ruoyi/common/result => ruoyi-system/src/main/java/com/ruoyi/system/domain/dto}/BOMUploadResult.java (95%) create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ConstructionDelayDTO.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/InspectionSheetDTO.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/OperationPlannDTO.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessInspectionDTO.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessReportDTO.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessTransferFormDTO.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProductionOrderDTO.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PartCostVo.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/PartCostMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/IPartCostService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/PartCostServiceImpl.java create mode 100644 ruoyi-system/src/main/resources/EXCEL模板/工序汇报未入库.xlsx create mode 100644 ruoyi-system/src/main/resources/EXCEL模板/工序转移数据.xlsx create mode 100644 ruoyi-system/src/main/resources/EXCEL模板/生产开工未领料模板.xlsx create mode 100644 ruoyi-system/src/main/resources/mapper/system/PartCostMapper.xml diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index a788a81..0238aea 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -167,6 +167,12 @@ org.bouncycastle bcprov-jdk15to18 + + com.hierynomus + smbj + 0.14.0 + + com.itextpdf diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java index e3bfa40..a27373e 100644 --- a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java @@ -34,6 +34,8 @@ public class SecurityConfig { .antMatchers("/system/proPlan/**").anonymous() .antMatchers("/system/mrp/**").anonymous() .antMatchers("/system/orderPro/**").anonymous() + .antMatchers("/system/cost/**").anonymous() + .antMatchers("/dev-api/system/cost/**").anonymous() // .antMatchers("/dev-api/system/proPlan/overdue").anonymous() // .antMatchers("/dev-api/system/proPlan/expiryProjects").anonymous() .antMatchers("/dev-api/system/material/list/").anonymous() diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml index b5d9c14..fc2d270 100644 --- a/ruoyi-system/pom.xml +++ b/ruoyi-system/pom.xml @@ -6,7 +6,7 @@ ruoyi-vue-plus com.ruoyi 4.7.0 - + org.apache.maven.pluginsmaven-compiler-plugin88 4.0.0 ruoyi-system 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 57d44de..4b97a28 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 @@ -21,21 +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.system.domain.dto.BOMItem; +import com.ruoyi.system.domain.dto.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.BomDetailsMapper; import com.ruoyi.system.mapper.ProcessOrderProMapper; import com.ruoyi.system.runner.JdUtil; import com.ruoyi.system.service.*; @@ -45,8 +44,6 @@ import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.WorkbookFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -84,8 +81,10 @@ public class BomDetailsController extends BaseController { private final IProcessOrderProService iProcessOrderProService; - private final IFigureSaveService iFigureSaveService; private final ProcessOrderProMapper processOrderProMapper; + + private final BomDetailsMapper bomDetailsMapper; + /** * 查询bom明细列表 */ @@ -382,27 +381,38 @@ public class BomDetailsController extends BaseController { for (BomDetails material : bomDetails) { // 获取工艺表中的非委外工时 Double fbWorkTime = iProcessRouteService.getFbWorkTime(material); - 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) { - log.info("新增物料成功 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName()); - material.setUnitWeight("新增成功"); - } else { - log.error("新增物料失败 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName()); + //判断bom类型是生产还是电气 + if (material.getBomType().equals("0")) { + try { + int result = loadMaterialPreservation(material, state, fbWorkTime); + if (result == 1) { + material.setUnitWeight("新增成功"); + } else { + failedMaterials.add(material.getPartNumber()); + } + // 更新物料状态 + iBomDetailsService.updateByBo(BeanUtil.toBean(material, BomDetailsBo.class)); + } catch (Exception e) { + failedMaterials.add(material.getPartNumber()); + } + } else { + try { + int result = loadMaterialToDQ(material, state); + if (result == 1) { + material.setUnitWeight("新增成功"); + } else { + failedMaterials.add(material.getPartNumber()); + } + // 更新物料状态 + iBomDetailsService.updateByBo(BeanUtil.toBean(material, BomDetailsBo.class)); + } catch (Exception e) { 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()); } } @@ -411,22 +421,20 @@ public class BomDetailsController extends BaseController { 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"); + logDTO.setCode("200"); + logDTO.setReason("成功上传"+"版本号:"+bomUploadResult.getNumber()); logDTOS.add(logDTO); } else { KindegeeLogDTO logDTO = new KindegeeLogDTO(); logDTO.setProjectCode(bo.getProductionOrderNo()); logDTO.setMaterialCode(fnumber); - logDTO.setMaterialName(fname); - logDTO.setCode(bomUploadResult.getNumber()); + logDTO.setCode("300"); logDTO.setReason(bomUploadResult.getErrorMessage()); logDTOS.add(logDTO); } @@ -439,8 +447,7 @@ public class BomDetailsController extends BaseController { KindegeeLogDTO logDTO = new KindegeeLogDTO(); logDTO.setProjectCode(bo.getProductionOrderNo()); logDTO.setMaterialCode(fnumber); - logDTO.setMaterialName(fname); - logDTO.setCode("200"); + logDTO.setCode("100"); logDTO.setReason("BOM已存在且一致"); logDTOS.add(logDTO); log.info("BOM已存在且一致,物料编码: {},跳过保存", fnumber); @@ -450,13 +457,14 @@ public class BomDetailsController extends BaseController { //更新项目进度 ProcessOrderPro processOrderProBo = iProcessOrderProService.selectByProjectNumber(totalWeight); - processOrderProBo.setDrawingType( JSONUtil.toJsonStr(logDTOS)); + processOrderProBo.setDrawingType(JSONUtil.toJsonStr(logDTOS)); processOrderProBo.setBomStatus(2L); processOrderProMapper.updateById(processOrderProBo); // 返回处理结果 return R.ok("成功", bomDetailsList); } + private boolean validateBOM(String fnumber, List bomDetails) { List JDBomList = JdUtil.getSelectBomList(fnumber); @@ -701,7 +709,7 @@ public class BomDetailsController extends BaseController { } // FBOM物料清单保存 - public BOMUploadResult FBloadBillOfMaterialsPreservation(List bomlist, ProcessOrderPro bo) { + public BOMUploadResult FBloadBillOfMaterialsPreservation(List bomlist, ProcessOrderPro bo) { BomDetails bomDetails1 = bomlist.get(0); int verification = isMaterialVerification(bomDetails1.getFNumber(), bomDetails1.getFName()); @@ -805,9 +813,7 @@ public class BomDetailsController extends BaseController { fTreeEntityItem.addProperty("F_HBYT_BJBM", details.getPartdiagramCode()); fTreeEntityItem.addProperty("F_HBYT_BJMC", details.getPartdiagramName()); fTreeEntityItem.addProperty("FDOSAGETYPE", "2"); - //判断这个在原材料表中单位如果是根,的话 那分子就是1 分母就是分子 - - fTreeEntityItem.addProperty("FNUMERATOR", details.getQuantity()); + fTreeEntityItem.addProperty("FNUMERATOR", details.getQuantity()); // 分子 fTreeEntityItem.addProperty("FDENOMINATOR", details.getDenominator()); // 添加货主信息 查看这个bom中是否符合货主信息 @@ -1724,7 +1730,10 @@ public class BomDetailsController extends BaseController { return 1; } - // 创建电气物料 + /** + * / 创建电气物料 + */ + public int loadMaterialToDQ(BomDetails bomDetails1, String states) { K3CloudApi client = new K3CloudApi(); // 创建一个空的JsonObject @@ -1738,7 +1747,8 @@ public class BomDetailsController extends BaseController { // 添加Model字段 model.addProperty("FMATERIALID", 0); - model.addProperty("FSpecification", bomDetails1.getRemarks());// 备注仓库 + model.addProperty("FSpecification", bomDetails1.getMaterial());// 规格 为存入的材质字段 + model.addProperty("F_HBYT_PP", bomDetails1.getWareHouse());// 品牌 为存入的仓库字段 model.addProperty("FNumber", bomDetails1.getPartNumber()); model.addProperty("FName", bomDetails1.getName()); MaterialProperties materialProperties = iMaterialPropertiesService.selectByAttribute(bomDetails1.getMaterial()); @@ -2108,10 +2118,9 @@ public class BomDetailsController extends BaseController { subHeadEntity1.add("FPickStockId", fPickStockId); subHeadEntity5.addProperty("FOverControlMode", "1"); - subHeadEntity5.addProperty("FStandHourUnitId", "3600"); + subHeadEntity5.addProperty("FStandHourUnitId", "60"); subHeadEntity5.addProperty("FBackFlushType", "1"); String jsonData = json.toString(); - System.out.println(jsonData); try { // 业务对象标识 String formId = "BD_MATERIAL"; @@ -2135,6 +2144,7 @@ public class BomDetailsController extends BaseController { } return 1; } + public BOMUploadResult parseK3Response(String jsonResponse) { try { ObjectMapper mapper = new ObjectMapper(); @@ -2166,20 +2176,61 @@ public class BomDetailsController extends BaseController { * @param file 导入文件 */ - @Log(title = "明细导入", businessType = BusinessType.IMPORT) - @SaCheckPermission("system:details:import") - @PostMapping(value = "/importData21", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public R importData21(@RequestPart("file") MultipartFile file) throws Exception { + @Log(title = "导入电气bom", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:details:importElectricalBom") + @PostMapping(value = "/importElectricalBom", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public void importElectricalBom(@RequestPart("file") MultipartFile file) throws Exception { List electricalMaterialBomVOS = ExcelUtil.importExcel(file.getInputStream(), ElectricalMaterialBomVO.class); + List list = new ArrayList<>(); 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()); + bomDetails.setFNumber(bomVO.getParentDrawingNo()); + bomDetails.setFName(bomVO.getParentPart()); + bomDetails.setPartNumber(bomVO.getDrawingNo()); + bomDetails.setName(bomVO.getDrawingName()); + bomDetails.setMaterial(bomVO.getModel());// + bomDetails.setWareHouse(bomVO.getBrand()); + bomDetails.setStats("外购"); + String quantity = bomVO.getQuantity().toString(); + bomDetails.setQuantity(quantity); + bomDetails.setRemarks(bomVO.getUnit()); + bomDetails.setUpdateTime(new Date()); + bomDetails.setBomType("1");//0 是生产bom 1 是电气bom + list.add(bomDetails); } - return null; + List bomDetailsVos1 = BeanUtil.copyToList(list, BomDetailsVo.class); + List bomDetails = saveBomDetails(bomDetailsVos1); + bomDetailsMapper.insertBatch(bomDetails); + + } + + // 保存到 BomDetails 表中 + //TODO: 使用本地库加速 + private List saveBomDetails(List bomDetailsVos) { + List materialsToAdd = new ArrayList<>(); + for (BomDetailsVo bomDetailsVo : bomDetailsVos) { + BomDetails bomDetails = BeanUtil.toBean(bomDetailsVo, BomDetails.class); + // 验证物料是否存在 + int materialVerification = isMaterialVerification(bomDetails.getPartNumber(), bomDetails.getName()); + if (materialVerification == 1) { + bomDetails.setUnitWeight("是"); + materialsToAdd.add(bomDetails); + } else if (materialVerification == 2) { + bomDetails.setUnitWeight("否"); + materialsToAdd.add(bomDetails); + } else if (materialVerification == 3) { + bomDetails.setUnitWeight("编码名称不符"); + materialsToAdd.add(bomDetails); + } + } + return materialsToAdd; + } + @Log(title = "推送工艺工序") + @SaCheckPermission("system:route:viewGetBomUploadStatus") + @PostMapping("/viewGetBomUploadStatus") + public R viewGetBomUploadStatus(@RequestParam String rooteProdet) { + return iProcessRouteService.viewGetBomUploadStatus(rooteProdet); } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomVariableController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomVariableController.java index d76f63a..bd3c1c0 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomVariableController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomVariableController.java @@ -267,7 +267,7 @@ public class BomVariableController extends BaseController { if (decimalIndex != -1) { quantityStr = quantityStr.substring(0, decimalIndex); } - bomDetails.setQuantity(Double.valueOf(quantityStr)); + bomDetails.setQuantity(quantityStr); } // 检查并转换单重 if (!rowData.get(5).isEmpty()) { diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ImMaterialController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ImMaterialController.java index 3707ac6..88bc4de 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ImMaterialController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ImMaterialController.java @@ -271,7 +271,7 @@ public class ImMaterialController extends BaseController { @XxlJob("updateMaterials") public Boolean updateMaterials() throws Exception { Date date = new Date(); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); List imMaterials = updateJdMaterial(sdf.format(date)); Boolean result = iImMaterialService.updateByFMid(imMaterials); return result; 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 3feff7d..7e529b9 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 @@ -2,8 +2,10 @@ package com.ruoyi.system.controller; import java.io.File; import java.time.LocalDate; +import java.time.temporal.ChronoUnit; import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.stream.Collectors; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateUtil; @@ -19,12 +21,14 @@ import com.ruoyi.common.utils.HttpRequestUtil; import com.ruoyi.common.utils.WxRobotUtil; import com.ruoyi.common.poi.ExcelTemplateProc; import com.ruoyi.common.poi.DynamicDataMapping; +import com.ruoyi.system.domain.ProcessRoute; import com.ruoyi.system.domain.SafetyStock; import com.ruoyi.system.domain.WlStockData; import com.ruoyi.system.domain.dto.*; import com.ruoyi.system.domain.vo.WlStockDataVo; import com.ruoyi.system.mapper.WlStockDataMapper; import com.ruoyi.system.runner.JdUtil; +import com.ruoyi.system.service.IProcessRouteService; import com.ruoyi.system.service.ISafetyStockService; import com.xxl.job.core.handler.annotation.XxlJob; import lombok.RequiredArgsConstructor; @@ -39,6 +43,7 @@ import cn.hutool.core.collection.CollUtil; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; import com.ruoyi.common.annotation.RepeatSubmit; @@ -74,7 +79,8 @@ public class KingdeeWorkCenterDataController extends BaseController { private static final Logger log = LoggerFactory.getLogger(KingdeeWorkCenterDataController.class); private final WlStockDataMapper baseMapper; private final ISafetyStockService iSafetyStockService; - + @Autowired + IProcessRouteService iProcessRouteService; /** * 查询金蝶工段数据列表 */ @@ -381,8 +387,9 @@ public class KingdeeWorkCenterDataController extends BaseController { msg.append("- ").append(workCenter).append(" (无数据)\n"); continue; } - - List dataList = result.getData(); + //加入暂停项目的过滤 + List dataList = result.getData().stream().filter(item -> item.getMoOrderNo() != null && !item.getMoOrderNo().contains("暂停")) + .collect(Collectors.toList()); msg.append("- ").append(workCenter).append(" (共").append(dataList.size()).append("条数据)\n"); // 生成Excel文件 @@ -433,10 +440,8 @@ public class KingdeeWorkCenterDataController extends BaseController { List kingdeeWorkCenterDataVos = new ArrayList<>(); parameter.addProperty("FWorkCenterName", workCenter); Object[] parameters = new Object[]{parameter.toString()}; - String execute = client.execute( - "Ljint.Kingdee.YiTe.KanBan.WebApi.ProduceWebApi.ExecuteService,Ljint.Kingdee.YiTe.KanBan.WebApi", - parameters); - log.info("金蝶接口返回数据: {}", execute); + String execute = client.execute("Ljint.Kingdee.YiTe.KanBan.WebApi.ProduceWebApi.ExecuteService,Ljint.Kingdee.YiTe.KanBan.WebApi121303", parameters); + log.info("金蝶接口:" + workCenter + "===> 返回数据: {}", execute); // 解析响应 JSONObject response = JSONObject.parseObject(execute); @@ -444,7 +449,6 @@ public class KingdeeWorkCenterDataController extends BaseController { String errorMsg = response.getString("Message"); return R.fail("获取工段数据失败:" + errorMsg); } - // 获取明天的日期字符串 (格式: yyyy-MM-dd) String yesterday = DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd"); @@ -518,26 +522,30 @@ public class KingdeeWorkCenterDataController extends BaseController { public R getMassageDelayDate() { try { // String robotId = "4d2f037d-0cee-493a-a4ff-1758f67b8069"; - String robotId = "483489b2-b219-468c-851f-f56a34a62d91"; + String robotId = "483489b2-b219-468c-851f-f56a34a62d91"; + // String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e"; List workCenters = Arrays.asList("机一工段", "机二工段", "机三工段", "装一工段", "装二工段", "委外中心", "电钳工段", "铆焊工段"); String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"); - StringBuilder msg = new StringBuilder(); - msg.append("🏭 延期数据更新提醒\n\n") - .append("更新时间:").append(currentTime).append("\n\n") - .append("🔧 工作中心数据统计:\n"); + // 构建Markdown消息 + StringBuilder markdownMsg = new StringBuilder(); + markdownMsg.append("# 生产延期数据更新提醒\n\n") + .append("> **统计时间:** ").append(currentTime).append("\n\n") + .append("## 🔧 工作中心数据统计:\n"); // 获取并统计每个工段的数据 for (String workCenter : workCenters) { try { R> result = getKingdeeDelayData(workCenter); + List data = result.getData(); if (R.isError(result) || CollUtil.isEmpty(result.getData())) { - msg.append("- ").append(workCenter).append(" (无数据)\n"); + markdownMsg.append("- ").append(workCenter).append(":无数据\n"); continue; } + List dataList = result.getData().stream().filter(item -> item.getMoOrderNo() != null && !item.getMoOrderNo().contains("暂停")) + .collect(Collectors.toList()); - List dataList = result.getData(); - msg.append("- ").append(workCenter).append(" (共").append(dataList.size()).append("条数据)\n"); + markdownMsg.append("- ").append(workCenter).append(":共 ").append(dataList.size()).append(" 条\n"); // 生成Excel文件 String fileName = String.format("%s生产延期数据_%s.xlsx", workCenter, @@ -558,12 +566,18 @@ public class KingdeeWorkCenterDataController extends BaseController { } catch (Exception e) { log.error("获取工段{}数据失败", workCenter, e); - msg.append("- ").append(workCenter).append(" (获取失败: ").append(e.getMessage()).append(")\n"); + markdownMsg.append("- ").append(workCenter).append(":获取失败: ").append(e.getMessage()).append("\n"); } } - msg.append("\n详细数据请查看发送的Excel文件!"); - wxRobotUtil.sendMsgToWeChatGroup(msg.toString(), robotId, true); // @所有人 + // 结尾提示与分段发送 + markdownMsg.append("\n> **📊 详细数据请查看发送的Excel文件!**"); + 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(); @@ -916,6 +930,7 @@ public class KingdeeWorkCenterDataController extends BaseController { map.put("FDate", item.getFDate()); map.put("FDeliveryDate", item.getFDeliveryDate()); map.put("FUCHNText2", item.getFUCHNText2()); + map.put("FCreateDate", item.getFCreateDate()); mapList.add(map); index++; } @@ -944,6 +959,7 @@ public class KingdeeWorkCenterDataController extends BaseController { map.put("FApplicationDate", item.getFApplicationDate()); map.put("FUCHNText", item.getFUCHNText()); map.put("FCreatorIdFName", item.getFCreatorIdFName()); + map.put("FCreateDate", item.getFCreateDate()); mapList.add(map); index++; } @@ -956,7 +972,6 @@ public class KingdeeWorkCenterDataController extends BaseController { */ private List filterPurchaseOrders(List allOrders) { LocalDate today = LocalDate.now(); - DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); log.info("开始过滤采购订单,总数: {}, 当前日期: {}", allOrders.size(), today.format(outputFormatter)); @@ -966,30 +981,45 @@ public class KingdeeWorkCenterDataController extends BaseController { String productionOrderNo = allOrder.getFUCHNText2(); String deliveryDate = allOrder.getFDeliveryDate(); - // 条件3: 交货日期不能为空,并且必须早于今天 + // ✅ 条件1: 暂停项目过滤 + if (productionOrderNo != null && productionOrderNo.contains("暂停")) { + log.debug("过滤掉: 暂停项目: {}", productionOrderNo); + continue; + } + + // ✅ 条件2: 交货日期不能为空 if (deliveryDate == null || deliveryDate.trim().isEmpty()) { log.debug("过滤掉: 交货日期为空"); continue; } try { - String dateStr = deliveryDate.split("T")[0]; // 取 yyyy-MM-dd 部分 - LocalDate delivery = LocalDate.parse(dateStr, inputFormatter); + // ✅ 格式化交货日期 + LocalDate delivery = parseDate(deliveryDate); + if (delivery == null) { + log.warn("解析交货日期失败: {}", deliveryDate); + continue; + } - // 转换格式 String formatted = delivery.format(outputFormatter); allOrder.setFDeliveryDate(formatted); + // ✅ 条件3: 只保留交货日期早于今天的 if (!delivery.isBefore(today)) { log.debug("过滤掉: 交货日期未过期: {}", formatted); continue; } - } catch (Exception e) { - log.warn("解析交货日期失败: {}", deliveryDate, e); - continue; - } + allOrder.setFQty(formatQty(allOrder.getFQty())); + // ✅ 顺便格式化其他日期字段 + allOrder.setFDate(formatDate(allOrder.getFDate())); + allOrder.setFDeliveryDate(formatDate(allOrder.getFDeliveryDate())); + allOrder.setFCreateDate(formatDate(allOrder.getFCreateDate())); - filteredOrders.add(allOrder); + filteredOrders.add(allOrder); + + } catch (Exception e) { + log.warn("处理订单异常: {}", productionOrderNo, e); + } } log.info("过滤完成,剩余数量: {}", filteredOrders.size()); @@ -1002,7 +1032,6 @@ public class KingdeeWorkCenterDataController extends BaseController { */ private List filterReqPurchaseOrders(List allOrders) { LocalDate today = LocalDate.now(); - DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); log.info("开始过滤采购申请订单,总数: {}, 当前日期: {}", allOrders.size(), today.format(outputFormatter)); @@ -1010,39 +1039,54 @@ public class KingdeeWorkCenterDataController extends BaseController { for (PurchaseRequestExcelDTO allOrder : allOrders) { String productionOrderNo = allOrder.getFUCHNText(); - String deliveryDate = allOrder.getFArrivalDate(); - if (allOrder.getFCloseStatus().equals("A")) { + String arrivalDate = allOrder.getFArrivalDate(); + + // 状态转换 + if ("A".equals(allOrder.getFCloseStatus())) { allOrder.setFCloseStatus("未关闭"); } - if (allOrder.getFDocumentStatus().equals("C")) { + if ("C".equals(allOrder.getFDocumentStatus())) { allOrder.setFDocumentStatus("已审核"); } + // 暂停项目过滤 + if (productionOrderNo != null && productionOrderNo.contains("暂停")) { + log.debug("过滤掉: 暂停项目: {}", productionOrderNo); + continue; + } - // 条件3: 交货日期不能为空,并且必须早于今天 - if (deliveryDate == null || deliveryDate.trim().isEmpty()) { - log.debug("过滤掉: 交货日期为空"); + // 到货日期不能为空 + if (arrivalDate == null || arrivalDate.trim().isEmpty()) { + log.debug("过滤掉: 到货日期为空"); continue; } try { - String dateStr = deliveryDate.split("T")[0]; // 取 yyyy-MM-dd 部分 - LocalDate delivery = LocalDate.parse(dateStr, inputFormatter); + LocalDate delivery = parseDate(arrivalDate); + if (delivery == null) { + log.warn("解析到货日期失败: {}", arrivalDate); + continue; + } - // 转换格式 + // 转换为中文日期格式 String formatted = delivery.format(outputFormatter); allOrder.setFArrivalDate(formatted); + // 只保留已过期的日期 if (!delivery.isBefore(today)) { - log.debug("过滤掉: 交货日期未过期: {}", formatted); + log.debug("过滤掉: 到货日期未过期: {}", formatted); continue; } - } catch (Exception e) { - log.warn("解析交货日期失败: {}", deliveryDate, e); - continue; - } + allOrder.setFReqQty(formatQty(allOrder.getFReqQty())); + allOrder.setFCreateDate(formatDate(allOrder.getFCreateDate())); + allOrder.setFApplicationDate(formatDate(allOrder.getFApplicationDate())); + allOrder.setFArrivalDate(formatDate(allOrder.getFArrivalDate())); - filteredOrders.add(allOrder); + filteredOrders.add(allOrder); + + } catch (Exception e) { + log.warn("处理订单异常: {}", productionOrderNo, e); + } } log.info("过滤完成,剩余数量: {}", filteredOrders.size()); @@ -1123,4 +1167,499 @@ public class KingdeeWorkCenterDataController extends BaseController { } } + /** + * 将日期字符串(如 "2025-09-22T10:52:03.6" 或 "2025-09-22")格式化为 "yyyy年MM月dd日" + */ + private String formatDate(String dateStr) { + if (dateStr == null || dateStr.isEmpty()) { + return null; + } + try { + LocalDate date = parseDate(dateStr); + if (date != null) { + return date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")); + } + } catch (Exception ignored) { + } + return dateStr; // 解析失败则返回原值 + } + + /** + * 解析日期字符串,支持带 T 的 ISO 格式或普通 yyyy-MM-dd 格式 + */ + private LocalDate parseDate(String dateStr) { + if (dateStr == null || dateStr.trim().isEmpty()) { + return null; + } + try { + // 先取出 T 之前的部分 + String clean = dateStr.split("T")[0]; + return LocalDate.parse(clean, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } catch (Exception e) { + log.debug("日期解析失败: {}", dateStr, e); + return null; + } + } + + /** + * 单据状态编码到中文的映射 + * A -> 创建,B -> 审核中,C -> 已审核,其它原样返回 + */ + private String mapDocumentStatus(String status) { + if (status == null || status.trim().isEmpty()) { + return ""; + } + switch (status) { + case "A": + return "创建"; + case "B": + return "审核中"; + case "C": + return "已审核"; + default: + return status; + } + } + + /** + * 格式化数量为两位小数 + */ + private String formatQty(String qtyStr) { + if (qtyStr == null || qtyStr.trim().isEmpty()) { + return "0.00"; + } + try { + double value = Double.parseDouble(qtyStr); + return String.format("%.2f", value); + } catch (NumberFormatException e) { + log.debug("数量格式化失败: {}", qtyStr, e); + return qtyStr; + } + } + + @Log(title = "获取开工延时的生产订单") + @XxlJob("getConstructionDelay") + @PostMapping("/getConstructionDelay") + public R getConstructionDelay() { + try { + + // String robotId = "4d2f037d-0cee-493a-a4ff-1758f67b8069"; + String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e"; + String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"); + StringBuilder msg = new StringBuilder(); + msg.append("🏭 生产订单未开工的延期通知\n\n").append("更新时间:").append(currentTime).append("\n\n").append("🔧 订单数据统计:\n"); + // 获取生产订单数据 + List purchaseOrderList1 = JdUtil.getConstructionDelay(); + + List purchaseOrderList = filterConstructionDel(purchaseOrderList1); + msg.append("- 到期未开工:").append(purchaseOrderList.size()).append("条\n"); + // 生成Excel文件使用采购模板 + String fileName = String.format("生产订单未开工的延期数据_%s.xlsx", DateUtil.format(new Date(), "yyyyMMddHHmmss")); + String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName; + // 准备模板数据 + Map staticDataMap = new HashMap<>(); + staticDataMap.put("currentTime", DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss")); + staticDataMap.put("purchaseOrderCount", purchaseOrderList.size()); + List dynamicDataMappingList = new ArrayList<>(); + // 添加数据(仅在此方法内映射,避免对已格式化日期再次格式化) + if (!purchaseOrderList.isEmpty()) { + List> orderDataList = new ArrayList<>(); + // 为避免循环中重复远程查询,增加简单的单号级缓存 + Map plannCache = new HashMap<>(); + int index = 1; + for (ConstructionDelayDTO item : purchaseOrderList) { + String billNo = item.getFBillNo(); + OperationPlannDTO plann = plannCache.get(billNo); + if (plann == null) { + try { + plann = JdUtil.getOperationPlann(billNo); + } catch (Exception ex) { + log.warn("获取工序汇报单失败,单号:{},原因:{}", billNo, ex.getMessage()); + } + plannCache.put(billNo, plann); // 即便为 null 也缓存,避免重复失败调用 + } + Map map = new HashMap<>(); + map.put("index", index++); + map.put("F_HBYT_SCLH", item.getF_HBYT_SCLH()); + map.put("FBillNo", item.getFBillNo()); + map.put("FPickMtrlStatus", item.getFPickMtrlStatus()); + map.put("FWorkShopIDFName", item.getFWorkShopIDFName()); + map.put("FMaterialIdFNumber", item.getFMaterialIdFNumber()); + map.put("FMaterialName", item.getFMaterialName()); + // 工序号/数量/工序名称做空值保护,避免因远程返回空导致 NPE + String operNumber = (plann != null && StringUtils.hasText(plann.getFOperNumber())) ? plann.getFOperNumber() : "-"; + String operQty = (plann != null && StringUtils.hasText(plann.getFOperQty())) ? formatQty(plann.getFOperQty()) : "-"; + String processName = (plann != null && StringUtils.hasText(plann.getFProcessIdFName())) ? plann.getFProcessIdFName() : "-"; + map.put("FOperNumber", operNumber); + map.put("FOperQty", operQty); + map.put("FProcessIdFName", processName); + map.put("FPlanStartDate", item.getFPlanStartDate()); + map.put("FPlanFinishDate", item.getFPlanFinishDate()); + map.put("Deydays", item.getDeydays()); + map.put("createTime", new Date()); + orderDataList.add(map); + } + dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ConstructionDelayDTO", orderDataList)); + } + // 使用采购模板生成Excel + String templatePath = "EXCEL模板/生产开工未领料模板.xlsx"; + ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, filePath, staticDataMap, dynamicDataMappingList); + // 发送Excel文件 + File excelFile = new File(filePath); + if (excelFile.exists()) { + wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId); + FileUtils.deleteQuietly(excelFile); + } + msg.append("\n详细数据请查看发送的Excel文件!"); + wxRobotUtil.sendMsgToWeChatGroup(msg.toString(), robotId, true); // @所有人 + + return R.ok(); + + } catch (Exception e) { + log.error("发送工段数据失败", e); + return R.fail("发送工段数据失败:" + e.getMessage()); + } + } + + + @Log(title = "工序汇报单订单-未入库") + @XxlJob("getProductionOrder") + @PostMapping("/getProductionOrder") + public R getProductionOrder() { + //TO DO: + + try { + String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e"; + String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"); + StringBuilder msg = new StringBuilder(); + msg.append("🏭 工序汇报未入库\n\n").append("更新时间:").append(currentTime).append("\n\n").append("🔧 订单数据统计:\n"); + + //工序汇报单,未入库列表 + List processReportDTOList = JdUtil.getProcessReport(); + msg.append("- 到期未开工:").append(processReportDTOList.size()).append("条\n"); + // 生成Excel文件使用采购模板 + String fileName = String.format("工序汇报未入库的延期数据_%s.xlsx", DateUtil.format(new Date(), "yyyyMMddHHmmss")); + String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName; + // 准备模板数据 + Map staticDataMap = new HashMap<>(); + staticDataMap.put("currentTime", DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss")); + staticDataMap.put("purchaseOrderCount", processReportDTOList.size()); + List dynamicDataMappingList = new ArrayList<>(); + // 添加数据(仅在此方法内映射,避免对已格式化日期再次格式化) + if (!processReportDTOList.isEmpty()) { + List> reportList = new ArrayList<>(); + int index = 1; + for (ProcessReportDTO item : processReportDTOList) { + Map map = new HashMap<>(); + map.put("index", index++); + map.put("FSCLH", item.getFSCLH()); + map.put("FBillNo", item.getFBillNo()); + map.put("FWorkShopID", item.getFWorkShopID()); + map.put("FMoNumber", item.getFMoNumber()); + map.put("FOperNumber", item.getFOperNumber()); + map.put("FOperDescription", item.getFOperDescription()); + map.put("FQuaQty", formatQty(item.getFQuaQty())); + map.put("FFinishQty", formatQty(item.getFFinishQty())); + map.put("FStockInQuaAuxQty", formatQty(item.getFStockInQuaAuxQty())); + map.put("FStockInFailAuxQty", formatQty(item.getFStockInFailAuxQty())); + map.put("FRKD", item.getFRKD()); + map.put("FDate", parseDate(item.getFDate())); + map.put("createTime", new Date()); + reportList.add(map); + } + dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessReportDTO", reportList)); + } + // 使用采购模板生成Excel + String templatePath = "EXCEL模板/工序汇报未入库.xlsx"; + ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, filePath, staticDataMap, dynamicDataMappingList); + // 发送Excel文件 + File excelFile = new File(filePath); + if (excelFile.exists()) { + wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId); + FileUtils.deleteQuietly(excelFile); + } + msg.append("\n详细数据请查看发送的Excel文件!"); + wxRobotUtil.sendMsgToWeChatGroup(msg.toString(), robotId, true); // @所有人 + + return R.ok(); + + } catch (Exception e) { + log.error("发送工段数据失败", e); + return R.fail("发送工段数据失败:" + e.getMessage()); + } + } + + + @Log(title = "工序转移未及时转移") + @XxlJob("getProcessTransferForm") + @PostMapping("/getProcessTransferForm") + public R getProcessTransferForm() { + //TO D0:需要查询工序计划的时间是否在今日 + try { + String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e"; + String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"); + // 构建 Markdown 消息 + StringBuilder markdownMsg = new StringBuilder(); + markdownMsg.append("🏭 **工序转移**\n\n"); + markdownMsg.append("- 📊 统计时间:").append(currentTime).append("\n"); + markdownMsg.append("- 📋 订单数据统计:\n"); + //工序汇报单,未入库列表 + List processReportDTOList = JdUtil.getProcessTransferForm(); + markdownMsg.append(" - 工序转移数据:").append(processReportDTOList.size()).append("条\n"); + // 追加Excel文件提示 + if (processReportDTOList.size() > 0) { + markdownMsg.append("\n📄 详细数据请查看发送的 Excel 文件\n"); + } + // 生成Excel文件使用采购模板 + String fileName = String.format("工序转移数据_%s.xlsx", DateUtil.format(new Date(), "yyyyMMddHHmmss")); + String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName; + // 准备模板数据 + Map staticDataMap = new HashMap<>(); + staticDataMap.put("currentTime", DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss")); + staticDataMap.put("purchaseOrderCount", processReportDTOList.size()); + List dynamicDataMappingList = new ArrayList<>(); + // 添加数据(仅在此方法内映射,避免对已格式化日期再次格式化) + if (!processReportDTOList.isEmpty()) { + + List> reportList = new ArrayList<>(); + int index = 1; + for (ProcessTransferFormDTO item : processReportDTOList) { + //ProcessRoute routes = iProcessRouteService.getProcessRoutesXuTime(item.getFSCLH(), item.getFProductIdNumber(), item.getFInOperNumber()); + /* Date inStart = (routes == null ? null : routes.getXuStartTime()); + Date createDate = null; + if (StringUtils.hasText(item.getFCreateDate())) { + try { + createDate = DateUtil.parse(item.getFCreateDate()); + } catch (Exception ignored) { } + } + // 当两者时间均可用时:仅过滤“未晚于转入序开始”的记录(即不延迟) + if (inStart != null && createDate != null && createDate.before(inStart)) { + continue; + }*/ + Map map = new HashMap<>(); + map.put("index", index++); + map.put("FSCLH", item.getFSCLH()); + map.put("FProductIdNumber", item.getFProductIdNumber()); + map.put("FDocumentStatus", mapDocumentStatus(item.getFDocumentStatus())); + map.put("FMOBillNo", item.getFMOBillNo()); + map.put("FBillNo", item.getFBillNo()); + map.put("FProductName", item.getFProductName()); + map.put("FOutDeptIdFName", item.getFOutDeptIdFName()); + map.put("FOutOperNumber", item.getFOutOperNumber()); + map.put("FOutProcessIdName", item.getFOutProcessIdName()); + map.put("FInDeptIdFName", item.getFInDeptIdFName()); + map.put("FInOperNumber", item.getFInOperNumber()); + map.put("FInProcessIdFName", item.getFInProcessIdFName()); + map.put("FOperUnit", item.getFOperUnit()); + map.put("FOperTransferQty", formatQty(item.getFOperTransferQty())); + map.put("FOperQualifiedQty", formatQty(item.getFOperQualifiedQty())); + map.put("FOperProFailQty", formatQty(item.getFOperProFailQty())); + map.put("FCreateDate", parseDate(item.getFCreateDate())); + map.put("createTime", new Date()); + reportList.add(map); + } + dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessTransferFormDTO", reportList)); + } + // 使用采购模板生成Excel + String templatePath = "EXCEL模板/工序转移数据.xlsx"; + ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, filePath, staticDataMap, dynamicDataMappingList); + // 发送消息 + wxRobotUtil.sendMarkdownMsgToWeChatGroup(markdownMsg.toString(), robotId); + + // 发送Excel文件 + File excelFile = new File(filePath); + if (excelFile.exists()) { + wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId); + FileUtils.deleteQuietly(excelFile); + } + + return R.ok(); + + } catch (Exception e) { + log.error("发送工段数据失败", e); + return R.fail("发送工段数据失败:" + e.getMessage()); + } + } + + private List> convertConstructionDelayToMapList(List purchaseOrderList) { + List> mapList = new ArrayList<>(); + int index = 1; + for (ConstructionDelayDTO item : purchaseOrderList) { + Map map = new HashMap<>(); + map.put("index", index); + + // —— 按照 ConstructionDelayDTO 字段 —— + map.put("F_HBYT_SCLH", item.getF_HBYT_SCLH()); // 生产令号 + map.put("FBillNo", item.getFBillNo()); // 单据编码(若有) + map.put("FWorkShopIDFName", item.getFWorkShopIDFName()); // 车间名称 + map.put("FMaterialIdFNumber", item.getFMaterialIdFNumber()); // 物料编码 + map.put("FMaterialName", item.getFMaterialName()); // 物料名称 + map.put("FPlanStartDate", formatDate(item.getFPlanStartDate())); // 计划开工时间(格式化) + map.put("FPlanFinishDate", formatDate(item.getFPlanFinishDate())); // 计划完工时间(格式化) + map.put("Deydays", item.getDeydays()); // 超期天数 + mapList.add(map); + index++; + } + return mapList; + } + + private List filterConstructionDel(List allPurchaseOrderList) { + LocalDate today = LocalDate.now(); + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); + + log.info("开始过滤生产订单,总数: {}, 当前日期: {}", allPurchaseOrderList.size(), today.format(outputFormatter)); + List filteredOrders = new ArrayList<>(); + + for (ConstructionDelayDTO allOrder : allPurchaseOrderList) { + String productionOrderNo = allOrder.getF_HBYT_SCLH(); + String deliveryDate = allOrder.getFPlanFinishDate(); + + // ✅ 条件1: 暂停项目过滤 + if (productionOrderNo != null && productionOrderNo.contains("暂停")) { + log.debug("过滤掉: 暂停项目: {}", productionOrderNo); + continue; + } // ✅ 条件1: 暂停项目过滤 + if (productionOrderNo == null || productionOrderNo.isEmpty()) { + log.debug("过滤掉: 无令号项目: {}", productionOrderNo); + continue; + } + try { + // ✅ 格式化交货日期 + LocalDate delivery = parseDate(deliveryDate); + if (delivery == null) { + log.warn("解析交货日期失败: {}", deliveryDate); + continue; + } + String formatted = delivery.format(outputFormatter); + allOrder.setFPlanFinishDate(formatted); + // ✅ 顺便格式化其他日期字段 + LocalDate planStart = parseDate(allOrder.getFPlanStartDate()); + if (planStart == null) { + log.warn("解析开工日期失败: {}", allOrder.getFPlanStartDate()); + continue; + } + // 计算过期天数:今天减去开工时间 + long delayDays = ChronoUnit.DAYS.between(planStart, today); + if (delayDays > 2) { + allOrder.setDeydays((int) delayDays); + allOrder.setFPlanStartDate(planStart.format(outputFormatter)); + allOrder.setFPlanFinishDate(formatted); + filteredOrders.add(allOrder); + } else { + log.debug("订单{} 延期{}天,不满足>2天条件,过滤", productionOrderNo, delayDays); + } + + } catch (Exception e) { + log.warn("处理订单异常: {}", productionOrderNo, e); + } + } + + log.info("过滤完成,剩余数量: {}", filteredOrders.size()); + return filteredOrders; + } + + /** + * 质检不及时数据 + */ + @XxlJob("getUninspectedData") + @Log(title = "质检不及时数据", businessType = BusinessType.DELETE) + @PostMapping("/getUninspectedData") + public R> getUninspectedData() { + try { + String robotId = "8af8abea-3f21-4ca7-ad0a-5b7a2cf4d78e"; + String currentTime = DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss"); + //工序汇报单,未入库列表 + List processReportDTOList = JdUtil.getUninspectedData(); + + // 构建Markdown消息 + StringBuilder markdownMsg = new StringBuilder(); + markdownMsg.append("# 工序质检不及时告警通知\n\n") + .append("> **统计时间:** ").append(currentTime).append("\n") + .append("> **未质检工序数量:** ").append(processReportDTOList.size()).append(" 条\n\n"); + + // 如果有未质检数据,显示前N条详细信息(默认3条) + if (!processReportDTOList.isEmpty()) { + markdownMsg.append("## 🔍 未质检工序详情(前2条)\n\n"); + int displayCount = Math.min(2, processReportDTOList.size()); + for (int i = 0; i < displayCount; i++) { + ProcessInspectionDTO item = processReportDTOList.get(i); + markdownMsg.append("### ").append(i + 1).append(". ").append(item.getFMaterialName()).append("\n") + .append("> **生产订单号:** ").append(item.getMoOrderNo()).append("\n") + .append("> **工序名称:** ").append(item.getFProcessName()).append("\n") + .append("> **工作中心:** ").append(item.getFWorkCenterName()).append("\n") + .append("> **检验状态:** ").append(item.getFInspectStatus()).append("\n") + .append("> **待检数量:** ").append(item.getFWaitInspectQty()).append("\n") + .append("> **已检数量:** ").append(item.getFFinishInspectQty()).append("\n") + .append("> **合格数量:** ").append(item.getFQuaQty()).append("\n") + .append("> **提交检验时间:** ").append(item.getFSubmitInspectTime()).append("\n\n"); + } + if (processReportDTOList.size() > displayCount) { + markdownMsg.append("> **注意:** 还有 ").append(processReportDTOList.size() - displayCount).append(" 条未质检记录,详细信息请查看Excel文件\n\n"); + } + } else { + markdownMsg.append("## ✅ 暂无未质检工序\n\n"); + } + + markdownMsg.append("> **创建时间:** ").append(DateUtil.formatDateTime(new Date())).append("\n"); + + // 追加Excel提示到Markdown消息 + markdownMsg.append("\n> **📊 详细数据请查看发送的Excel文件!**"); + // 生成Excel文件使用采购模板 + String fileName = String.format("工序未质检数据_%s.xlsx", DateUtil.format(new Date(), "yyyyMMddHHmmss")); + String filePath = FileUtils.getTempDirectoryPath() + File.separator + fileName; + // 准备模板数据 + Map staticDataMap = new HashMap<>(); + staticDataMap.put("currentTime", DateUtil.format(new Date(), "yyyy年MM月dd日 HH:mm:ss")); + staticDataMap.put("purchaseOrderCount", processReportDTOList.size()); + List dynamicDataMappingList = new ArrayList<>(); + // 添加数据(仅在此方法内映射,避免对已格式化日期再次格式化) + if (!processReportDTOList.isEmpty()) { + List> reportList = new ArrayList<>(); + int index = 1; + for (ProcessInspectionDTO item : processReportDTOList) { + Map map = new HashMap<>(); + map.put("index", index++); + map.put("moBillNo", item.getMoBillNo()); + map.put("moOrderNo", item.getMoOrderNo()); + map.put("fMaterialName", item.getFMaterialName()); + map.put("fProcessName", item.getFProcessName()); + map.put("fWorkCenterName", item.getFWorkCenterName()); + map.put("fInspectStatus", item.getFInspectStatus()); + map.put("fWaitInspectQty", item.getFWaitInspectQty()); + map.put("fFinishInspectQty", item.getFFinishInspectQty()); + map.put("fQuaQty", item.getFQuaQty()); + map.put("fReworkQty", item.getFReworkQty()); + map.put("fFailQty", item.getFFailQty()); + map.put("fSubmitInspectTime", item.getFSubmitInspectTime()); + map.put("fFinishInspectTime", item.getFFinishInspectTime()); + map.put("fDescription", parseDate(item.getFDescription())); + reportList.add(map); + } + dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessInspectionDTO", reportList)); + } + // 使用采购模板生成Excel + String templatePath = "EXCEL模板/质检模板.xlsx"; + ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, filePath, staticDataMap, dynamicDataMappingList); + // 发送Excel文件 + File excelFile = new File(filePath); + if (excelFile.exists()) { + wxRobotUtil.sendFileToWeChatGroup(excelFile, robotId); + FileUtils.deleteQuietly(excelFile); + } + // 发送Markdown消息(企业微信要求使用 msgtype=markdown),并按长度分段 + 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(); + + } catch (Exception e) { + log.error("发送工段数据失败", e); + return R.fail("发送工段数据失败:" + e.getMessage()); + } + } + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/PartCostController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PartCostController.java new file mode 100644 index 0000000..e148f09 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PartCostController.java @@ -0,0 +1,119 @@ +package com.ruoyi.system.controller; + +import java.util.List; +import java.util.Arrays; + +import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.PageQuery; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.system.domain.vo.PartCostVo; +import com.ruoyi.system.domain.bo.PartCostBo; +import com.ruoyi.system.service.IPartCostService; +import com.ruoyi.common.core.page.TableDataInfo; + +/** + * 零件成本 + * + * @author 田志阳 + * @date 2025-10-24 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/cost") +public class PartCostController extends BaseController { + + private final IPartCostService iPartCostService; + + /** + * 查询零件成本列表 + */ + @SaCheckPermission("system:cost:list") + @GetMapping("/list") + public TableDataInfo list(PartCostBo bo, PageQuery pageQuery) { + return iPartCostService.queryPageList(bo, pageQuery); + } + + /** + * 导出零件成本列表 + */ + @SaCheckPermission("system:cost:export") + @Log(title = "零件成本", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(PartCostBo bo, HttpServletResponse response) { + List list = iPartCostService.queryList(bo); + ExcelUtil.exportExcel(list, "零件成本", PartCostVo.class, response); + } + + /** + * 获取零件成本详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:cost:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(iPartCostService.queryById(id)); + } + + /** + * 新增零件成本 + */ + @SaCheckPermission("system:cost:add") + @Log(title = "零件成本", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody PartCostBo bo) { + return toAjax(iPartCostService.insertByBo(bo)); + } + + /** + * 修改零件成本 + */ + @SaCheckPermission("system:cost:edit") + @Log(title = "零件成本", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody PartCostBo bo) { + return toAjax(iPartCostService.updateByBo(bo)); + } + + /** + * 删除零件成本 + * + * @param ids 主键串 + */ + @SaCheckPermission("system:cost:remove") + @Log(title = "零件成本", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(iPartCostService.deleteWithValidByIds(Arrays.asList(ids), true)); + } + + + + /** + * 在金蝶获取成本价 + */ + @SaCheckPermission("system:cost:getObtainPartData") + @Log(title = "在金蝶获取成本价", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/getObtainPartData") + public R getObtainPartData() { + return toAjax(iPartCostService.getObtainPartData()); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/PcRigidChainController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PcRigidChainController.java index f5f0032..d99e4dd 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/PcRigidChainController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PcRigidChainController.java @@ -170,9 +170,8 @@ public class PcRigidChainController extends BaseController { DefaultExcelListener excelListener = new DefaultExcelListener<>(true); EasyExcel.read(new ByteArrayInputStream(fileBytes), PcRigidChainVo.class, excelListener) - .excelType(ExcelTypeEnum.XLS) .sheet(readSheet.getSheetNo()) - .headRowNumber(4) + .headRowNumber(3) .doRead(); List list = excelListener.getExcelResult().getList(); @@ -214,38 +213,6 @@ public class PcRigidChainController extends BaseController { 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"); @@ -254,34 +221,8 @@ public class PcRigidChainController extends BaseController { dbChain.setType(type); dbChain.setBox(box); dbChain.setAxialDirection(s); - 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); log.info("物料: {} 已添加到更新列表", typeName); @@ -301,27 +242,7 @@ public class PcRigidChainController extends BaseController { 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()); - + pcRigidChain.setUpdateTime(new Date()); int i = pcRigidChainMapper.updateById(pcRigidChain); if (i > 0) { successCount++; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java index 964faee..53c8d0f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java @@ -236,10 +236,14 @@ public class ProcessOrderProController extends BaseController { */ @SaCheckPermission("system:processOrderPro:uploadPDF") - @Log(title = "上传PDF", businessType = BusinessType.UPDATE) + @Log(title = "下载PDF", businessType = BusinessType.UPDATE) + @CrossOrigin(origins = "*", allowedHeaders = "*", exposedHeaders = {"Content-Disposition", "Content-Length"}) @GetMapping("/uploadPDF") public void uploadPDF(@RequestParam Long id, HttpServletResponse response) { try { + // CORS headers for all responses (success and error) + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Length"); // 调用service方法获取文件路径 R result = iProcessOrderProService.uploadPDF(id); if (result.getCode() != 200) { @@ -264,6 +268,7 @@ public class ProcessOrderProController extends BaseController { response.setContentType("application/zip"); response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(file.getName(), "UTF-8") + "\""); response.setHeader("Content-Length", String.valueOf(file.length())); + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition, Content-Length"); // 写入文件流 try (FileInputStream fis = new FileInputStream(file); @@ -343,6 +348,7 @@ public class ProcessOrderProController extends BaseController { public List getOverdueProjects() { return iProcessOrderProService.getOverdueProjects(); } + @SaCheckPermission("system:orderPro:geMRPResults") @Log(title = "获取MRP复核结果", businessType = BusinessType.OTHER) @PostMapping("/getMRPResults/{id}") @@ -423,7 +429,6 @@ public class ProcessOrderProController extends BaseController { } } - // 电气外包分类条件:物料编码开头空格/特定前缀 或 备注包含"外购" if (materialCode.startsWith(" ") || materialCode.startsWith("009301") || materialCode.startsWith("009999") @@ -541,11 +546,11 @@ public class ProcessOrderProController extends BaseController { // 总装部件优先 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; @@ -652,7 +657,6 @@ public class ProcessOrderProController extends BaseController { if (row == null) { continue; } - ProcessRoute vo = new ProcessRoute(); // 根据列索引读取数据,保留原始空格 @@ -747,9 +751,7 @@ public class ProcessOrderProController extends BaseController { if (row == null) { continue; } - ProductionOrderVo vo = new ProductionOrderVo(); - // 根据列索引读取数据,保留原始空格 vo.setId(getCellValueAsLong(row.getCell(0))); vo.setDrawingNo(getCellValueAsString(row.getCell(1))); // 图号 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessRouteController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessRouteController.java index f15f33b..14ec26d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessRouteController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessRouteController.java @@ -443,7 +443,7 @@ public class ProcessRouteController extends BaseController { @Log(title = "推送工艺工序") @SaCheckPermission("system:route:pushRouteBom") @PostMapping("/pushRouteBom") - public ProcessRoutePushResultDTO pushRouteBom(@RequestParam String rooteProdet) { + public R pushRouteBom(@RequestParam String rooteProdet) { return iProcessRouteService.pushRouteBom(rooteProdet); } @@ -644,7 +644,7 @@ public class ProcessRouteController extends BaseController { materialBom.setUnit(materialUsageDTO.getChildUnit()); materialBom.setMaterialType(materialUsageDTO.getCaizhi()); //保留四位小数 - materialBom.setQuantity(String.valueOf(new BigDecimal(materialUsageDTO.getFenzi()).divide(new BigDecimal(materialUsageDTO.getFenmu()),4, RoundingMode.HALF_UP))); + materialBom.setQuantity(String.valueOf(BigDecimal.valueOf(materialUsageDTO.getFenzi()).divide(new BigDecimal(materialUsageDTO.getFenmu()),4, RoundingMode.HALF_UP))); return materialBom; } @@ -658,7 +658,7 @@ public class ProcessRouteController extends BaseController { bomDetails.setUnitWeight("是"); bomDetails.setWareHouse(materialUsageDTO.getChildUnit()); //子项分子 - bomDetails.setQuantity(materialUsageDTO.getFenzi()); + bomDetails.setQuantity(String.valueOf(materialUsageDTO.getFenzi())); //子项分母 bomDetails.setDenominator(Double.valueOf(materialUsageDTO.getFenmu())); bomDetails.setName(materialUsageDTO.getMaterialName()); @@ -801,7 +801,7 @@ public class ProcessRouteController extends BaseController { bomDetails.setUnitWeight("是"); bomDetails.setWareHouse(materialUsageDTO.getUnit()); //子项分子 - bomDetails.setQuantity(materialUsageDTO.getFNumerator()); + bomDetails.setQuantity(String.valueOf(materialUsageDTO.getFNumerator())); //子项分母 bomDetails.setDenominator(materialUsageDTO.getFDenominator()); bomDetails.setName(materialUsageDTO.getMaterialName()); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/BomDetails.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/BomDetails.java index 73ea2a7..e605705 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/BomDetails.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/BomDetails.java @@ -76,7 +76,7 @@ public class BomDetails extends BaseEntity { * 子项分子 */ @JsonProperty("FNUMERATOR") - private Double quantity; + private String quantity; /** * 子项分母 */ @@ -106,4 +106,8 @@ public class BomDetails extends BaseEntity { * 子项单重 */ private Double singleWeghit; + /** + *bom类型 + */ + private String bomType; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/PartCost.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/PartCost.java new file mode 100644 index 0000000..147ee12 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/PartCost.java @@ -0,0 +1,72 @@ +package com.ruoyi.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 零件成本对象 part_cost + * + * @author 田志阳 + * @date 2025-10-24 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("part_cost") +public class PartCost extends BaseEntity { + + private static final long serialVersionUID=1L; + + /** + * ID + */ + @TableId(value = "id") + private Long id; + /** + * 物料编码 + */ + @JsonProperty("FMaterialId.FNumber") + private String materialCode; + /** + * 物料名称 + */ + @JsonProperty("FMaterialName") + private String materialName; + /** + * 成本价 + */ + @JsonProperty("FPrice") + private BigDecimal costPrice; + /** + * 创建日期 + */ + @JsonProperty("FCreateDate") + private Date createDate; + /** + * 车间 + */ + @JsonProperty("FEntryWorkShopId.FName") + private String workshop; + /** + * 单位 + */ + @JsonProperty("FUnitID.FName") + private String unit; + /** + * 仓库 + */ + @JsonProperty("FStockId.FName") + private String warehouse; + /** + * 规格型号 + */ + @JsonProperty("FSpecification") + private String specificationModel; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/BomDetailsBo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/BomDetailsBo.java index 8dd9c55..7f8e441 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/BomDetailsBo.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/BomDetailsBo.java @@ -79,4 +79,8 @@ public class BomDetailsBo extends BaseEntity { * 单重 */ private Double danzhong; + /** + *bom类型 + */ + private String bomType; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/PartCostBo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/PartCostBo.java new file mode 100644 index 0000000..c031874 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/PartCostBo.java @@ -0,0 +1,88 @@ +package com.ruoyi.system.domain.bo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; +import javax.validation.constraints.*; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 零件成本业务对象 part_cost + * + * @author 田志阳 + * @date 2025-10-24 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class PartCostBo extends BaseEntity { + + /** + * ID + */ + @NotNull(message = "ID不能为空", groups = { EditGroup.class }) + + private Long id; + + /** + * 物料编码 + */ + @NotBlank(message = "物料编码不能为空", groups = { AddGroup.class, EditGroup.class }) + @JsonProperty("FMaterialId.FNumber") + private String materialCode; + + /** + * 物料名称 + */ + @NotBlank(message = "物料名称不能为空", groups = { AddGroup.class, EditGroup.class }) + @JsonProperty("FMaterialName") + private String materialName; + + /** + * 成本价 + */ + @NotNull(message = "成本价不能为空", groups = { AddGroup.class, EditGroup.class }) + @JsonProperty("FPrice") + private BigDecimal costPrice; + + /** + * 创建日期 + */ + @NotNull(message = "创建日期不能为空", groups = { AddGroup.class, EditGroup.class }) + @JsonProperty("FCreateDate") + private Date createDate; + + /** + * 车间 + */ + @NotBlank(message = "车间不能为空", groups = { AddGroup.class, EditGroup.class }) + @JsonProperty("FEntryWorkShopId.FName") + private String workshop; + + /** + * 单位 + */ + @NotBlank(message = "单位不能为空", groups = { AddGroup.class, EditGroup.class }) + @JsonProperty("FUnitID.FName") + private String unit; + + /** + * 仓库 + */ + @NotBlank(message = "仓库不能为空", groups = { AddGroup.class, EditGroup.class }) + @JsonProperty("FStockId.FName") + private String warehouse; + /** + * 规格型号 + */ + @NotBlank(message = "规格型号", groups = { AddGroup.class, EditGroup.class }) + @JsonProperty("FSpecification") + private String specificationModel; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/BOMItem.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/BOMItem.java new file mode 100644 index 0000000..fa05565 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/BOMItem.java @@ -0,0 +1,10 @@ +package com.ruoyi.system.domain.dto; + +import lombok.Data; + +import java.util.List; +@Data +public class BOMItem { + int id; + private List items; +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/result/BOMUploadResult.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/BOMUploadResult.java similarity index 95% rename from ruoyi-common/src/main/java/com/ruoyi/common/result/BOMUploadResult.java rename to ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/BOMUploadResult.java index 45f9c0b..59033bd 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/result/BOMUploadResult.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/BOMUploadResult.java @@ -1,4 +1,4 @@ -package com.ruoyi.common.result; +package com.ruoyi.system.domain.dto; import lombok.Data; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ConstructionDelayDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ConstructionDelayDTO.java new file mode 100644 index 0000000..f6d3fcc --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ConstructionDelayDTO.java @@ -0,0 +1,48 @@ +package com.ruoyi.system.domain.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Date; + +@Data +public class ConstructionDelayDTO { + //生产令号 + @JsonProperty("F_HBYT_SCLH") + private String F_HBYT_SCLH; + //单据编码 + @JsonProperty("FBillNo") + private String FBillNo; + //车间名称 + @JsonProperty("FWorkShopID.FName") + private String FWorkShopIDFName; + //物料编码 + @JsonProperty("FMaterialId.FNumber") + private String FMaterialIdFNumber; + //物料名称 + @JsonProperty("FMaterialName") + private String FMaterialName; + //计划开工时间 + @JsonProperty("FPlanStartDate") + private String FPlanStartDate; + //计划完工时间 + @JsonProperty("FPlanFinishDate") + private String FPlanFinishDate; + //计划完工时间 + @JsonProperty("FPickMtrlStatus") + private String FPickMtrlStatus; + //超期天数 + private int Deydays; + + @JsonProperty("FOperNumber") + private String FOperNumber; + + @JsonProperty("FOperQty") + private String FOperQty; + + @JsonProperty("FOutProcessId.FName") + private String FProcessIdFName; + + + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/InspectionSheetDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/InspectionSheetDTO.java new file mode 100644 index 0000000..e7ecd59 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/InspectionSheetDTO.java @@ -0,0 +1,64 @@ +package com.ruoyi.system.domain.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 质检检验单数据 + * @author tzy + * @date 2025-10-26 + */ + +@Data +public class InspectionSheetDTO { + //生产令号 + @JsonProperty("F_UCHN_Text") + private String productionOrderNumber; + + //单据编码 + @JsonProperty("FBillNo") + private String FBillNo; + + //单据状态 + @JsonProperty("FDocumentStatus") + private String DocumentStatus; + + //物料编码 + @JsonProperty("FMaterialId.FNumber") + private String FMaterialIdFNumber; + + //物料名称 + @JsonProperty("FMaterialName") + private String FMaterialName; + + //规格型号 + @JsonProperty("FMaterialModel") + private String FMaterialModel; + + //质检状态 + @JsonProperty("FQCStatus") + private String FQCStatus; + + // 检验结果 + @JsonProperty("FInspectResult") + private String FInspectResult; + + // 单位 + @JsonProperty("FUnitID.FName") + private String FUnitIDFName; + + // 检验数量 + @JsonProperty("FInspectQty") + private String FInspectQty; + + // 合格数 + @JsonProperty("FQualifiedQty") + private String FQualifiedQty; + + // 不合格数 + @JsonProperty("FUnqualifiedQty") + private String FUnqualifiedQty; + + //超期天数 + private int Deydays; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/OperationPlannDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/OperationPlannDTO.java new file mode 100644 index 0000000..8241a0f --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/OperationPlannDTO.java @@ -0,0 +1,18 @@ +package com.ruoyi.system.domain.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class OperationPlannDTO { + + @JsonProperty("FOperNumber") + private String FOperNumber; + + @JsonProperty("FOperQty") + private String FOperQty; + + @JsonProperty("FOutProcessId.FName") + private String FProcessIdFName; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessInspectionDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessInspectionDTO.java new file mode 100644 index 0000000..1745d22 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessInspectionDTO.java @@ -0,0 +1,51 @@ +package com.ruoyi.system.domain.dto; + +import lombok.Data; + +@Data +public class ProcessInspectionDTO { + /** 单编号 */ + private String moBillNo; + + /** 生产订单号 */ + private String moOrderNo; + + /** 子订单号 */ + private String subOrderNo; + + /** 物料名称 */ + private String fMaterialName; + + /** 工序名称 */ + private String fProcessName; + + /** 工作中心(工段)名称 */ + private String fWorkCenterName; + + /** 检验状态(如:未完成、已完成) */ + private String fInspectStatus; + + /** 待检数量 */ + private Integer fWaitInspectQty; + + /** 已检验数量 */ + private Integer fFinishInspectQty; + + /** 合格数量 */ + private Integer fQuaQty; + + /** 返工数量 */ + private Integer fReworkQty; + + /** 报废数量 */ + private Integer fFailQty; + + /** 提交检验时间(字符串格式,如 "12-24") */ + private String fSubmitInspectTime; + + /** 完成检验时间(字符串格式) */ + private String fFinishInspectTime; + + /** 备注或描述 */ + private String fDescription; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessReportDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessReportDTO.java new file mode 100644 index 0000000..34c9d5c --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessReportDTO.java @@ -0,0 +1,60 @@ +package com.ruoyi.system.domain.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 工序汇报单实体 + * @author tzy + * @date 2025-10-28 + */ +@Data +public class ProcessReportDTO { + //生产令号 + @JsonProperty("F_HBYT_SCLH") + private String FSCLH; + + //单据编号 + @JsonProperty("FBillNo") + private String FBillNo; + + //加工车间 + @JsonProperty("FWorkShopID.FName") + private String FWorkShopID; + + //工序号 + @JsonProperty("FOperNumber") + private String FOperNumber; + //工序说明 + @JsonProperty("FOperDescription") + private String FOperDescription; + + + //合格数量 + @JsonProperty("FQuaQty") + private String FQuaQty; + //合格数量 + @JsonProperty("FMoNumber") + private String FMoNumber; + + // 完工数量 + @JsonProperty("FFinishQty") + private String FFinishQty; + + // 合格品入库数量 + @JsonProperty("FStockInQuaAuxQty") + private String FStockInQuaAuxQty; + + //不合格品入库数量 + @JsonProperty("FStockInFailAuxQty") + private String FStockInFailAuxQty; + + //入库点 + @JsonProperty("F_HBYT_RKD") + private String FRKD; + + //单据日期 + @JsonProperty("FDate") + private String FDate; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessRouteXuDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessRouteXuDTO.java index a4081a4..d8d4698 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessRouteXuDTO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessRouteXuDTO.java @@ -19,6 +19,11 @@ public class ProcessRouteXuDTO { * 工序路线描述 */ private String processDescription; + /** + * + */ + private String errorMessage; + /** * 工艺路线 */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessTransferFormDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessTransferFormDTO.java new file mode 100644 index 0000000..8302b3c --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessTransferFormDTO.java @@ -0,0 +1,77 @@ +package com.ruoyi.system.domain.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 工序转移单 + * @author tzy + * @date 2025-10-28 + */ +@Data +public class ProcessTransferFormDTO { + + //生产令号 + @JsonProperty("F_HBYT_SCLH") + private String FSCLH; + //单据编码 + @JsonProperty("FBillNo") + private String FBillNo; + //单据编码 + @JsonProperty("FDocumentStatus") + private String FDocumentStatus; + //单据编码 + @JsonProperty("FMOBillNo") + private String FMOBillNo; + //产品编码 + @JsonProperty("FProductId.FNumber") + private String FProductIdNumber; + + //产品名称 + @JsonProperty("FProductName") + private String FProductName; + + //转出加工车间 + @JsonProperty("FOutDeptId.FName") + private String FOutDeptIdFName; + + //转出工序计划号 + @JsonProperty("FOutOperNumber") + private String FOutOperNumber; + + //转出作业 + @JsonProperty("FOutProcessId.FName") + private String FOutProcessIdName; + + //转入加工车间 + @JsonProperty("FInDeptId.FName") + private String FInDeptIdFName; + + //转入工序计划号 + @JsonProperty("FInOperNumber") + private String FInOperNumber; + + //转入作业 + @JsonProperty("FInProcessId.FName") + private String FInProcessIdFName; + + //工序单位 + @JsonProperty("FOperUnitId.FName") + private String FOperUnit; + + //转移数量 + @JsonProperty("FOperTransferQty") + private String FOperTransferQty; + + //合格数量 + @JsonProperty("FOperQualifiedQty") + private String FOperQualifiedQty; + + //工废数量 + @JsonProperty("FOperProFailQty") + private String FOperProFailQty; + + //创建日期 + @JsonProperty("FCreateDate") + private String FCreateDate; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProductionOrderDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProductionOrderDTO.java new file mode 100644 index 0000000..9aeaddc --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProductionOrderDTO.java @@ -0,0 +1,70 @@ +package com.ruoyi.system.domain.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + + +/** + * 生产订单开工未领料数据 + * @author tzy + * @date 2025-10-26 + */ + +@Data +public class ProductionOrderDTO { + + //生产令号 + @JsonProperty("F_HBYT_SCLH") + private String productionOrderNumber; + + //单据编码 + @JsonProperty("FBillNo") + private String FBillNo; + + //单据状态 + @JsonProperty("FDocumentStatus") + private String DocumentStatus; + + //物料编码 + @JsonProperty("FMaterialId.FNumber") + private String FMaterialIdFNumber; + + //物料名称 + @JsonProperty("FMaterialName") + private String FMaterialName; + + //材质 + @JsonProperty("F_UCHN_BaseProperty_qtr") + private String material; + + //单位 + @JsonProperty("FUnitId.FName") + private String unit; + + //生产车间 + @JsonProperty("FWorkShopID.FName") + private String productionWorkshop; + + //数量 + @JsonProperty("FQty") + private String quantity; + + //业务状态 + @JsonProperty("FStatus") + private String businessStatus; + + //领料状态 + @JsonProperty("FPickMtrlStatus") + private String materialRequisitionStatus; + + //计划开工时间 + @JsonProperty("FPlanStartDate") + private String FPlanStartDate; + + //计划完工时间 + @JsonProperty("FPlanFinishDate") + private String FPlanFinishDate; + + //超期天数 + private int Deydays; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PurchaseOrderExcelDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PurchaseOrderExcelDTO.java index c08eeb6..8f9e72e 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PurchaseOrderExcelDTO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PurchaseOrderExcelDTO.java @@ -52,5 +52,10 @@ public class PurchaseOrderExcelDTO { */ @JsonProperty("F_UCHN_Text2") private String FUCHNText2; + /** + * 创建日期 + */ + @JsonProperty("FCreateDate") + private String FCreateDate; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PurchaseRequestExcelDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PurchaseRequestExcelDTO.java index 316bb92..7f38fa1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PurchaseRequestExcelDTO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/PurchaseRequestExcelDTO.java @@ -79,11 +79,17 @@ public class PurchaseRequestExcelDTO { * 生产令号 */ @JsonProperty("F_UCHN_Text") - private String FUCHNText;/** + private String FUCHNText; + /** * 生产令号 */ @JsonProperty("FCreatorId.FName") private String FCreatorIdFName; + /** + * 创建日期 + */ + @JsonProperty("FCreateDate") + private String FCreateDate; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/BomDetailsVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/BomDetailsVo.java index b81c08b..6e8ddbb 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/BomDetailsVo.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/BomDetailsVo.java @@ -103,5 +103,8 @@ public class BomDetailsVo { private Double danZhong; private Double singleWeghit; - + /** + *bom类型 + */ + private String bomType; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElectricalMaterialBomVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElectricalMaterialBomVO.java index 9edc78e..01edf56 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElectricalMaterialBomVO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElectricalMaterialBomVO.java @@ -41,7 +41,7 @@ public class ElectricalMaterialBomVO { * 品牌 */ @ExcelProperty(value = "品牌") - private Double Brand; + private String Brand; /** * 单台数量 @@ -58,7 +58,7 @@ public class ElectricalMaterialBomVO { * 单位 */ @ExcelProperty(value = "单位") - private Double unit; + private String unit; /** * 备注 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PartCostVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PartCostVo.java new file mode 100644 index 0000000..a84f1c8 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PartCostVo.java @@ -0,0 +1,79 @@ +package com.ruoyi.system.domain.vo; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; +import lombok.Data; + + +/** + * 零件成本视图对象 part_cost + * + * @author 田志阳 + * @date 2025-10-24 + */ +@Data +@ExcelIgnoreUnannotated +public class PartCostVo { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @ExcelProperty(value = "ID") + + private Long id; + + /** + * 物料编码 + */ + @ExcelProperty(value = "物料编码") + + private String materialCode; + + /** + * 物料名称 + */ + @ExcelProperty(value = "物料名称") + private String materialName; + + /** + * 成本价 + */ + @ExcelProperty(value = "成本价") + private BigDecimal costPrice; + + /** + * 创建日期 + */ + @ExcelProperty(value = "创建日期") + private Date createDate; + + /** + * 车间 + */ + @ExcelProperty(value = "车间") + private String workshop; + + /** + * 单位 + */ + @ExcelProperty(value = "单位") + private String unit; + + /** + * 仓库 + */ + @ExcelProperty(value = "仓库") + private String warehouse; + /** + * 规格型号 + */ + @ExcelProperty(value = "规格型号") + private String specificationModel; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/PartCostMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/PartCostMapper.java new file mode 100644 index 0000000..75840f1 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/PartCostMapper.java @@ -0,0 +1,15 @@ +package com.ruoyi.system.mapper; + +import com.ruoyi.system.domain.PartCost; +import com.ruoyi.system.domain.vo.PartCostVo; +import com.ruoyi.common.core.mapper.BaseMapperPlus; + +/** + * 零件成本Mapper接口 + * + * @author 田志阳 + * @date 2025-10-24 + */ +public interface PartCostMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/runner/JdUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/runner/JdUtil.java index ffb28d6..8680350 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/runner/JdUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/runner/JdUtil.java @@ -1,5 +1,7 @@ package com.ruoyi.system.runner; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; @@ -8,8 +10,10 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.kingdee.bos.webapi.entity.RepoRet; import com.kingdee.bos.webapi.sdk.K3CloudApi; +import com.ruoyi.common.core.domain.R; import com.ruoyi.common.utils.JdUtils; import com.ruoyi.system.domain.BomDetails; +import com.ruoyi.system.domain.PartCost; import com.ruoyi.system.domain.dto.*; import com.ruoyi.system.domain.vo.*; import com.ruoyi.system.jdmain.rouplan.Model; @@ -312,7 +316,7 @@ public class JdUtil { try { String resultJson = String.valueOf(client.billQuery(jsonData)); System.out.println( - // "生成查询计划订单查询 " + planOrder.getFBillNo() + " 的结果: " + resultJson + // "生成查询计划订单查询 " + planOrder.getFBillNo() + " 的结果: " + resultJson ); JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); if (jsonArray == null || jsonArray.size() == 0) { @@ -419,7 +423,7 @@ public class JdUtil { try { String resultJson = String.valueOf(client.billQuery(jsonData)); System.out.println( - // "生成查询计划订单查询 " + planOrder.getFBillNo() + " 的结果: " + resultJson + // "生成查询计划订单查询 " + planOrder.getFBillNo() + " 的结果: " + resultJson ); JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); if (jsonArray == null || jsonArray.size() == 0) { @@ -499,7 +503,7 @@ public class JdUtil { JsonObject resultObject = new Gson().fromJson(resultJson, JsonObject.class); JsonArray rows = resultObject.getAsJsonObject("Result").getAsJsonArray("Rows"); - if (rows == null){ + if (rows == null) { System.err.println("No data returned for materialCode: " + materialCode); return new ArrayList<>(); } @@ -519,26 +523,29 @@ public class JdUtil { return rptDTOS; } - private static String getStringFromJsonArray(JsonArray array, int index) { - return array.size() > index && !array.get(index).isJsonNull() ? array.get(index).getAsString() : ""; - } - private static double getDoubleFromJsonArray(JsonArray array, int index) { - if (array.size() > index && !array.get(index).isJsonNull()) { - String value = array.get(index).getAsString(); - if (!value.isEmpty()) { - try { - return Double.parseDouble(value); - } catch (NumberFormatException e) { - System.err.println("NumberFormatException for value: " + value); - } + private static String getStringFromJsonArray(JsonArray array, int index) { + return array.size() > index && !array.get(index).isJsonNull() ? array.get(index).getAsString() : ""; + } + + private static double getDoubleFromJsonArray(JsonArray array, int index) { + if (array.size() > index && !array.get(index).isJsonNull()) { + String value = array.get(index).getAsString(); + if (!value.isEmpty()) { + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + System.err.println("NumberFormatException for value: " + value); } } - return 0.0; } + return 0.0; + } + /** * 查询生产订单单据体 - *查询 + * 查询 + * * @param materialCode * @return */ @@ -584,7 +591,7 @@ public class JdUtil { filterObject3.addProperty("Right", ""); filterObject3.addProperty("Logic", 0); filterString.add(filterObject3); - JsonObject filterObject4 = new JsonObject(); + JsonObject filterObject4 = new JsonObject(); filterObject4.addProperty("FieldName", "FNoStockInQty"); filterObject4.addProperty("Compare", "21"); // 改为等号运算符 filterObject4.addProperty("Value", 0); @@ -619,14 +626,16 @@ public class JdUtil { return promoList; // 返回结果 } + /** * 查询生产订单未入库 本项目除外 - *查询 + * 查询 + * * @param materialCode * @return */ - public static List getProMoListLimitByProCode(String materialCode,String proCode) { + public static List getProMoListLimitByProCode(String materialCode, String proCode) { K3CloudApi client = new K3CloudApi(); // 请求参数,要求为json字符串 JsonObject json = new JsonObject(); @@ -709,14 +718,16 @@ public class JdUtil { return promoList; // 返回结果 } + /** * 查询生产订单未入库 本项目 - *查询 + * 查询 + * * @param materialCode * @return */ - public static List getProMoListByProCode(String materialCode,String proCode) { + public static List getProMoListByProCode(String materialCode, String proCode) { K3CloudApi client = new K3CloudApi(); // 请求参数,要求为json字符串 JsonObject json = new JsonObject(); @@ -799,9 +810,11 @@ public class JdUtil { return promoList; // 返回结果 } + /** * 查询采购订单 单据体 * 将预留量更改为 剩余未入库数量20250325 + * * @param materialCode * @return */ @@ -860,14 +873,16 @@ public class JdUtil { return plannedProcessList; // 返回结果 } + /** * 查询采购订单 单据体 * 将预留量更改为 剩余未入库数量20250325 + * * @param materialCode * @return */ - public static List getPurchaseOrderListByProCode(String materialCode,String proCode) { + public static List getPurchaseOrderListByProCode(String materialCode, String proCode) { K3CloudApi client = new K3CloudApi(); @@ -929,7 +944,8 @@ public class JdUtil { return plannedProcessList; // 返回结果 } - public static List getPurchaseRequestByProCode(String materialCode,String proCode) { + + public static List getPurchaseRequestByProCode(String materialCode, String proCode) { K3CloudApi client = new K3CloudApi(); @@ -983,8 +999,9 @@ public class JdUtil { return plannedProcessList; // 返回结果 } + // 采购申请(本项目除外) - public static List getPurchaseRequestByLimitProCode(String materialCode,String proCode) { + public static List getPurchaseRequestByLimitProCode(String materialCode, String proCode) { K3CloudApi client = new K3CloudApi(); @@ -1038,13 +1055,15 @@ public class JdUtil { return plannedProcessList; // 返回结果 } + /** * 查询生产用料清单单据体 * 查询子项物料的未领料量 + * * @param materialCode * @return */ - public static List getWeiLingliaoLimBen(String materialCode,String procode) { + public static List getWeiLingliaoLimBen(String materialCode, String procode) { K3CloudApi client = new K3CloudApi(); @@ -1130,9 +1149,11 @@ public class JdUtil { return plannedProcessList; // 返回结果 } + /** * 查询生产用料清单单据体 * 查询子项物料的未领料量 + * * @param materialCode * @return */ @@ -1215,13 +1236,15 @@ public class JdUtil { return plannedProcessList; // 返回结果 } + /** * 查询生产用料清单单据体 * 查询子项物料的未领料量限制生产令号 + * * @param materialCode * @return */ - public static List getWeiLingliaoByProcode(String materialCode,String procode) { + public static List getWeiLingliaoByProcode(String materialCode, String procode) { K3CloudApi client = new K3CloudApi(); @@ -1308,6 +1331,7 @@ public class JdUtil { return plannedProcessList; // 返回结果 } + public static List getKuCun(String materialCode) { K3CloudApi client = new K3CloudApi(); @@ -1355,8 +1379,9 @@ public class JdUtil { return plannedProcessList; // 返回结果 } + public static Double getKeyong(String materialCode) { - List analyzeRpt =getInvReserveAnalyzeRpt(materialCode); + List analyzeRpt = getInvReserveAnalyzeRpt(materialCode); if (analyzeRpt.isEmpty()) { System.err.println("No inventory data found for materialCode: " + materialCode); return 0.0; // 返回 0.0 而不是 null @@ -1385,6 +1410,7 @@ public class JdUtil { } return fSecAVBQty + productionQty + purchaseQty - fSecQty; } + // 金蝶物料查询 public static int isMaterialVerification(String DrawingNumber, String name) { if (DrawingNumber == null || DrawingNumber.isEmpty() || name == null || name.isEmpty()) { @@ -1409,10 +1435,11 @@ public class JdUtil { return 1; // 编码未找到,返回1表示正常 } } + /*本接口用于实现物料清单 的禁用功能*/ public static void jtestForbidMaterial(String FNumber) throws Exception { K3CloudApi api = new K3CloudApi(); - String data = "{\"CreateOrgId\": 0,\"Numbers\": ["+"\""+FNumber+"\""+"],\"Ids\": \"\",\"PkEntryIds\":[],\"NetworkCtrl\": \"\",\"IgnoreInterationFlag\": \"\"}"; + String data = "{\"CreateOrgId\": 0,\"Numbers\": [" + "\"" + FNumber + "\"" + "],\"Ids\": \"\",\"PkEntryIds\":[],\"NetworkCtrl\": \"\",\"IgnoreInterationFlag\": \"\"}"; String result = api.excuteOperation("ENG_BOM", "Forbid", data); Gson gson = new Gson(); RepoRet repoRet = gson.fromJson(result, RepoRet.class); @@ -1423,6 +1450,7 @@ public class JdUtil { fail("物料提交接口: " + gson.toJson(repoRet.getResult())); } } + //用料清单查询接口腹肌无聊 public static List getFuji(String materialCode) { List jinYongDTOS = new ArrayList<>(); @@ -1456,7 +1484,8 @@ public class JdUtil { if (jsonArray != null && jsonArray.size() > 0) { ObjectMapper objectMapper = new ObjectMapper(); List JinYongDTOList = objectMapper.readValue(jsonArray.toString(), - new TypeReference>() {}); + new TypeReference>() { + }); if (JinYongDTOList != null && !JinYongDTOList.isEmpty()) { jinYongDTOS.addAll(JinYongDTOList); } @@ -1469,6 +1498,7 @@ public class JdUtil { return jinYongDTOS; } + //查询物料 FMATERIALID SubHeadEntity5FEntryId public static List getEntryID(String materialCode) { List jinYongDTOS = new ArrayList<>(); @@ -1502,7 +1532,8 @@ public class JdUtil { if (jsonArray != null && jsonArray.size() > 0) { ObjectMapper objectMapper = new ObjectMapper(); List JinYongDTOList = objectMapper.readValue(jsonArray.toString(), - new TypeReference>() {}); + new TypeReference>() { + }); if (JinYongDTOList != null && !JinYongDTOList.isEmpty()) { jinYongDTOS.addAll(JinYongDTOList); } @@ -1515,8 +1546,9 @@ public class JdUtil { return jinYongDTOS; } + //修改物料工时,固定单位=分 - public static void atestSaveMaterial(int FMATERIALID,int fEntryId,String materialCode ,double laborTime) throws Exception { + public static void atestSaveMaterial(int FMATERIALID, int fEntryId, String materialCode, double laborTime) throws Exception { K3CloudApi api = new K3CloudApi(false); // 创建主 JSON 对象 JsonObject mainObject = new JsonObject(); @@ -1555,8 +1587,8 @@ public class JdUtil { mainObject.add("NeedReturnFields", needReturnFields); // 将 Model 添加到主对象 mainObject.add("Model", modelObject); - String data = mainObject.toString(); - String result = api.save("BD_Material", data); + String data = mainObject.toString(); + String result = api.save("BD_Material", data); Gson gson = new Gson(); RepoRet sRet = gson.fromJson(result, RepoRet.class); if (sRet.isSuccessfully()) { @@ -1565,8 +1597,9 @@ public class JdUtil { fail("物料保存接口: " + gson.toJson(sRet.getResult())); } } + //新增父级物料 - public static int loadChengPinMaterialPreservation(BomDetails bomDetail, Double fbWorkTime ) { + public static int loadChengPinMaterialPreservation(BomDetails bomDetail, Double fbWorkTime) { K3CloudApi client = new K3CloudApi(); // 创建一个空的JsonObject JsonObject json = new JsonObject(); @@ -1580,7 +1613,7 @@ public class JdUtil { // 添加Model字段 model.addProperty("FMATERIALID", 0); - if(!(bomDetail.getDanZhong() ==null)){ + if (!(bomDetail.getDanZhong() == null)) { model.addProperty("F_HBYT_DZ", bomDetail.getDanZhong()); } model.addProperty("FNumber", bomDetail.getFNumber()); @@ -1726,6 +1759,7 @@ public class JdUtil { } } + //查询物料 作用于更新到物料的 仓位 是否启用VMI public static List getEntryID2(String materialCode) { List jinYongDTOS = new ArrayList<>(); @@ -1760,7 +1794,8 @@ public class JdUtil { if (jsonArray != null && jsonArray.size() > 0) { ObjectMapper objectMapper = new ObjectMapper(); List entryVmis = objectMapper.readValue(jsonArray.toString(), - new TypeReference>() {}); + new TypeReference>() { + }); if (entryVmis != null && !entryVmis.isEmpty()) { jinYongDTOS.addAll(entryVmis); } @@ -1773,6 +1808,7 @@ public class JdUtil { return jinYongDTOS; } + //更新VMI public static String updateVMI(int FMATERIALID, int fEntryId1, int fEntryId2, String cangkunum, String cangWeiNum) throws Exception { K3CloudApi api = new K3CloudApi(false); @@ -1811,7 +1847,7 @@ public class JdUtil { JsonObject fStockPlaceIdFF100002 = new JsonObject(); fStockPlaceIdFF100002.addProperty("FNumber", cangWeiNum); // - // fStockPlaceId.add("FSTOCKPLACEID__FF100002", fStockPlaceIdFF100002); + // fStockPlaceId.add("FSTOCKPLACEID__FF100002", fStockPlaceIdFF100002); fStockPlaceId.add("FSTOCKPLACEID__FF100002", fStockPlaceIdFF100002); subHeadEntity1.add("FStockPlaceId", fStockPlaceId); @@ -1839,6 +1875,7 @@ public class JdUtil { return errorMessage; } } + public static void updateDanzhong(int FMATERIALID, String danzhong) throws Exception { K3CloudApi api = new K3CloudApi(false); JsonObject json = new JsonObject(); @@ -1869,6 +1906,7 @@ public class JdUtil { System.out.println(errorMessage); } } + //查询物料清单 的 行iD public static List getFID(String materialCode) { List jinYongDTOS = new ArrayList<>(); @@ -1902,7 +1940,8 @@ public class JdUtil { if (jsonArray != null && jsonArray.size() > 0) { ObjectMapper objectMapper = new ObjectMapper(); List JinYongDTOList = objectMapper.readValue(jsonArray.toString(), - new TypeReference>() {}); + new TypeReference>() { + }); if (JinYongDTOList != null && !JinYongDTOList.isEmpty()) { jinYongDTOS.addAll(JinYongDTOList); } @@ -1915,8 +1954,9 @@ public class JdUtil { return jinYongDTOS; } + //更新物料清单 的 行ID - public static String updateHuozhu(int FID, int FENTRYID,String code) throws Exception { + public static String updateHuozhu(int FID, int FENTRYID, String code) throws Exception { K3CloudApi api = new K3CloudApi(false); JsonObject json = new JsonObject(); @@ -1959,14 +1999,15 @@ public class JdUtil { RepoRet sRet = gson.fromJson(result, RepoRet.class); if (sRet.isSuccessfully()) { String successMessage = String.format("物料清单 %s 保存成功", sRet.getResult().getResponseStatus()); - log.info("更新货主信息物料编码==>"+code+" 保存成功"); + log.info("更新货主信息物料编码==>" + code + " 保存成功"); return successMessage; } else { String errorMessage = String.format("物料 %s 保存失败: %s", FENTRYID, gson.toJson(sRet.getResult())); - log.info("更新货主信息物料编码"+code+"保存失败"+"原因:"+gson.toJson(sRet.getResult())); + log.info("更新货主信息物料编码" + code + "保存失败" + "原因:" + gson.toJson(sRet.getResult())); return errorMessage; } } + //查询物料清单 的 行iD public static JdHuoZhu getFIDToProductionOrder(PlanOrderVo planOrder) { K3CloudApi client = new K3CloudApi(); @@ -1999,7 +2040,8 @@ public class JdUtil { if (jsonArray != null && jsonArray.size() > 0) { ObjectMapper objectMapper = new ObjectMapper(); List jinYongDTOList = objectMapper.readValue(jsonArray.toString(), - new TypeReference>() {}); + new TypeReference>() { + }); if (jinYongDTOList != null && !jinYongDTOList.isEmpty()) { return jinYongDTOList.get(0); // 返回第一个对象 } @@ -2012,6 +2054,7 @@ public class JdUtil { return null; // 如果没有找到,返回 null } + //保存更新生产订单的开工时间 public static String updateOrder(JdHuoZhu jdHuoZhu, Model numDTO, Date xuStartTime, Date xuEndTime) throws Exception { String planStartDate = dateFormat.format(xuStartTime); @@ -2051,16 +2094,17 @@ public class JdUtil { RepoRet sRet = gson.fromJson(result, RepoRet.class); if (sRet.isSuccessfully()) { String successMessage = String.format("生产订单 %s 保存成功", sRet.getResult().getResponseStatus()); - log.info("物料编码"+numDTO.getFID()+"保存成功"); + log.info("物料编码" + numDTO.getFID() + "保存成功"); return successMessage; } else { String errorMessage = String.format("物料 %s 保存失败: %s", +numDTO.getFID(), gson.toJson(sRet.getResult())); - log.info("物料编码"+numDTO.getFID()+"保存失败"+"原因:"+gson.toJson(sRet.getResult())); + log.info("物料编码" + numDTO.getFID() + "保存失败" + "原因:" + gson.toJson(sRet.getResult())); return errorMessage; } } + public static List getSubHeadEntity1Id(String materialCode) { - ListsubHeadEntityDTOS = new ArrayList<>(); + List subHeadEntityDTOS = new ArrayList<>(); K3CloudApi client = new K3CloudApi(); JsonObject json = new JsonObject(); json.addProperty("FormId", "BD_MATERIAL"); @@ -2092,7 +2136,8 @@ public class JdUtil { if (jsonArray != null && jsonArray.size() > 0) { ObjectMapper objectMapper = new ObjectMapper(); List JinYongDTOList = objectMapper.readValue(jsonArray.toString(), - new TypeReference>() {}); + new TypeReference>() { + }); if (JinYongDTOList != null && !JinYongDTOList.isEmpty()) { subHeadEntityDTOS.addAll(JinYongDTOList); } @@ -2105,7 +2150,8 @@ public class JdUtil { return subHeadEntityDTOS; } - public static String updateKunCun(int FMATERIALID, int fEntryId1, int fMaxPOQty, int FSafeStock) throws Exception { + + public static String updateKunCun(int FMATERIALID, int fEntryId1, int fMaxPOQty, int FSafeStock) throws Exception { K3CloudApi api = new K3CloudApi(false); JsonObject json = new JsonObject(); @@ -2156,6 +2202,7 @@ public class JdUtil { return errorMessage; } } + //获取用料清单 根据父级物料编码,作为bom校验使用 public static List getSelectBomList(String FMaterialCode) { K3CloudApi client = new K3CloudApi(); @@ -2201,7 +2248,8 @@ public class JdUtil { return null; } } - public static String updateOldFuNumber(String FMATERIALID, String FNumber, String FOldNumber) throws Exception { + + public static String updateOldFuNumber(String FMATERIALID, String FNumber, String FOldNumber) throws Exception { K3CloudApi api = new K3CloudApi(false); JsonObject json = new JsonObject(); @@ -2246,8 +2294,8 @@ public class JdUtil { JsonObject obj = element.getAsJsonObject(); String key = obj.get("FID").getAsString() + "_" + - obj.get("FMATERIALID.FNumber").getAsString() + "_" + - obj.get("FITEMNAME").getAsString(); + obj.get("FMATERIALID.FNumber").getAsString() + "_" + + obj.get("FITEMNAME").getAsString(); JdValidateBomDTO parentDTO = bomMap.computeIfAbsent(key, k -> { JdValidateBomDTO dto = new JdValidateBomDTO(); dto.setFID(obj.get("FID").getAsString()); @@ -2277,8 +2325,10 @@ public class JdUtil { return new ArrayList<>(); } } + /** * 获取生产用料清单 + * * @param F_HBYT_SCLH * @return */ @@ -2327,6 +2377,7 @@ public class JdUtil { return materialUsageDTO2List; // 返回结果 } + //用料清单查询接口腹肌无聊 public static List getEngBom(String materialCode) { List jinYongDTOS = new ArrayList<>(); @@ -2360,7 +2411,8 @@ public class JdUtil { if (jsonArray != null && jsonArray.size() > 0) { ObjectMapper objectMapper = new ObjectMapper(); List JinYongDTOList = objectMapper.readValue(jsonArray.toString(), - new TypeReference>() {}); + new TypeReference>() { + }); if (JinYongDTOList != null && !JinYongDTOList.isEmpty()) { jinYongDTOS.addAll(JinYongDTOList); } @@ -2377,6 +2429,7 @@ public class JdUtil { /** * 获取固定工艺路线 + * * @param FMaterialCode * @return */ @@ -2419,7 +2472,8 @@ public class JdUtil { if (jsonArray != null && jsonArray.size() > 0) { ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readValue(jsonArray.toString(), new TypeReference>() {}); + return objectMapper.readValue(jsonArray.toString(), new TypeReference>() { + }); } else { return Collections.emptyList(); } @@ -2428,8 +2482,10 @@ public class JdUtil { } return Collections.emptyList(); } + /** * 获取物料清单 + * * @param FMaterialCode * @return */ @@ -2469,7 +2525,8 @@ public class JdUtil { JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); if (jsonArray != null && jsonArray.size() > 0) { ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readValue(jsonArray.toString(), new TypeReference>() {}); + return objectMapper.readValue(jsonArray.toString(), new TypeReference>() { + }); } else { return Collections.emptyList(); } @@ -2478,8 +2535,10 @@ public class JdUtil { } return Collections.emptyList(); } + /** * 查询金蝶资产卡片 + * * @return */ @@ -2522,7 +2581,7 @@ public class JdUtil { // 请求参数,要求为json字符串 JsonObject json = new JsonObject(); json.addProperty("FormId", "PUR_PurchaseOrder"); - json.addProperty("FieldKeys", "FBillNo,FDate,FSupplierId.FName,FMaterialId.FNumber,FMaterialName,FQty,FDeliveryDate,F_UCHN_Text2"); + json.addProperty("FieldKeys", "FBillNo,FDate,FSupplierId.FName,FMaterialId.FNumber,FMaterialName,FQty,FDeliveryDate,F_UCHN_Text2,FCreateDate"); // 创建过滤条件 JsonObject filterObject = new JsonObject(); JsonArray filterString = new JsonArray(); @@ -2579,14 +2638,13 @@ public class JdUtil { /** * 采购申请单 - * @return List */ public static List getPurchaseRequestOrder() { K3CloudApi client = new K3CloudApi(); // 请求参数,要求为json字符串 JsonObject json = new JsonObject(); json.addProperty("FormId", "PUR_Requisition"); - json.addProperty("FieldKeys", "FBillNo,FBillTypeID,FDocumentStatus,FCloseStatus,FSuggestPurDate,FSuggestSupplierId.FName,FMaterialId.FNumber,FMaterialName,FPriceUnitId.FName,FReqQty,FArrivalDate,FApplicationDate,F_UCHN_Text,FCreatorId.FName"); + json.addProperty("FieldKeys", "FBillNo,FBillTypeID,FDocumentStatus,FCloseStatus,FSuggestPurDate,FSuggestSupplierId.FName,FMaterialId.FNumber,FMaterialName,FCreateDate,FPriceUnitId.FName,FReqQty,FArrivalDate,FApplicationDate,F_UCHN_Text,FCreatorId.FName"); // 创建过滤条件 JsonObject filterObject = new JsonObject(); JsonArray filterString = new JsonArray(); @@ -2631,4 +2689,538 @@ public class JdUtil { return purchaseRequestExcelDTOList; // 返回结果 } + + public static List getConstructionDelay() { + K3CloudApi client = new K3CloudApi(); + // 请求参数,要求为json字符串 + JsonObject json = new JsonObject(); + json.addProperty("FormId", "PRD_MO"); + json.addProperty("FieldKeys", "F_HBYT_SCLH,FBillNo,FWorkShopID.FName,FMaterialId.FNumber,FMaterialName,FPlanStartDate,FPlanFinishDate,FPickMtrlStatus"); + // 创建过滤条件 + JsonObject filterObject = new JsonObject(); + JsonArray filterString = new JsonArray(); + filterObject.addProperty("FieldName", "FStatus"); + filterObject.addProperty("Compare", "105"); + filterObject.addProperty("Value", "4"); + filterObject.addProperty("Left", ""); + filterObject.addProperty("Right", ""); + filterObject.addProperty("Logic", 0); + filterString.add(filterObject); + + JsonObject filterObject1 = new JsonObject(); + filterObject1.addProperty("FieldName", "FPickMtrlStatus"); + filterObject1.addProperty("Compare", "29"); + filterObject1.addProperty("Value", "1"); + filterObject1.addProperty("Left", ""); + filterObject1.addProperty("Right", ""); + filterObject1.addProperty("Logic", 0); + filterString.add(filterObject1); + + json.add("FilterString", filterString); + json.addProperty("OrderString", ""); + json.addProperty("TopRowCount", 0); + json.addProperty("StartRow", 0); + json.addProperty("Limit", 10000); + json.addProperty("SubSystemId", ""); + + List constructionDelayDTOList = new ArrayList<>(); + int pageSize = 10000; + int startRow = 0; + ObjectMapper objectMapper = new ObjectMapper(); + try { + while (true) { + JsonObject pageJson = new Gson().fromJson(json.toString(), JsonObject.class); + pageJson.addProperty("StartRow", startRow); + pageJson.addProperty("Limit", pageSize); + String resultJson = String.valueOf(client.billQuery(pageJson.toString())); + JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); + if (jsonArray == null || jsonArray.size() == 0) { + break; + } + List pageList = objectMapper.readValue( + jsonArray.toString(), new TypeReference>() { + }); + constructionDelayDTOList.addAll(pageList); + if (jsonArray.size() < pageSize) { + break; + } + startRow += pageSize; + } + } catch (Exception e) { + e.printStackTrace(); // 输出异常日志 + } + + return constructionDelayDTOList; // 返回结果 + } + + public static List getObtainPartData() { + K3CloudApi client = new K3CloudApi(); + // 请求参数,要求为json字符串 + JsonObject json = new JsonObject(); + json.addProperty("FormId", "PRD_PickMtrl"); + json.addProperty("FieldKeys", "FMaterialId.FNumber,FSpecification,FMaterialName,FPrice,FCreateDate,FEntryWorkShopId.FName,FUnitID.FName,FStockId.FName"); + // 创建过滤条件 + JsonObject filterObject = new JsonObject(); + JsonArray filterString = new JsonArray(); + filterObject.addProperty("FieldName", "FDocumentStatus"); + filterObject.addProperty("Compare", "105"); + filterObject.addProperty("Value", "C"); + filterObject.addProperty("Left", ""); + filterObject.addProperty("Right", ""); + filterObject.addProperty("Logic", 0); + filterString.add(filterObject); + + json.add("FilterString", filterString); + json.addProperty("OrderString", ""); + json.addProperty("TopRowCount", 0); + json.addProperty("StartRow", 0); + json.addProperty("Limit", 10000); + json.addProperty("SubSystemId", ""); + + List partCostBoList = new ArrayList<>(); + int pageSize = 10000; + int startRow = 0; + ObjectMapper objectMapper = new ObjectMapper(); + try { + while (true) { + JsonObject pageJson = new Gson().fromJson(json.toString(), JsonObject.class); + pageJson.addProperty("StartRow", startRow); + pageJson.addProperty("Limit", pageSize); + String resultJson = String.valueOf(client.billQuery(pageJson.toString())); + JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); + if (jsonArray == null || jsonArray.size() == 0) { + break; + } + List pageList = objectMapper.readValue(jsonArray.toString(), new TypeReference>() { + }); + partCostBoList.addAll(pageList); + if (jsonArray.size() < pageSize) { + break; + } + startRow += pageSize; + } + } catch (Exception e) { + e.printStackTrace(); // 输出异常日志 + } + + return partCostBoList; // 返回结果 + } + + /** + * 获取生产订单开工未领料数据 + * 不包含暂停状态的项目 + */ + public static List getProductionOrder() { + K3CloudApi client = new K3CloudApi(); + // 请求参数,要求为json字符串 + JsonObject json = new JsonObject(); + json.addProperty("FormId", "PRD_MO"); + json.addProperty("FieldKeys", "F_HBYT_SCLH,FBillNo,FDocumentStatus,FMaterialId.FNumber,FMaterialName,F_UCHN_BaseProperty_qtr,FUnitId.FName,FWorkShopID.FName,FQty,FStatus,FPickMtrlStatus,FPlanStartDate,FPlanFinishDate"); + // 创建过滤条件 + JsonObject filterObject = new JsonObject(); + JsonArray filterString = new JsonArray(); + filterObject.addProperty("FieldName", "FPickMtrlStatus"); + filterObject.addProperty("Compare", "29"); + filterObject.addProperty("Value", "1"); + filterObject.addProperty("Left", ""); + filterObject.addProperty("Right", ""); + filterObject.addProperty("Logic", 0); + filterString.add(filterObject); + + JsonObject filterObject1 = new JsonObject(); + filterObject1.addProperty("FieldName", "F_HBYT_SCLH"); + filterObject1.addProperty("Compare", "34"); + filterObject1.addProperty("Value", "暂停"); + filterObject1.addProperty("Left", ""); + filterObject1.addProperty("Right", ""); + filterObject1.addProperty("Logic", 0); + filterString.add(filterObject1); + + json.add("FilterString", filterString); + json.addProperty("OrderString", ""); + json.addProperty("TopRowCount", 0); + json.addProperty("StartRow", 0); + json.addProperty("Limit", 10000); + json.addProperty("SubSystemId", ""); + List productionOrderDTOList = new ArrayList<>(); + int pageSize = 10000; + int startRow = 0; + ObjectMapper objectMapper = new ObjectMapper(); + try { + while (true) { + JsonObject pageJson = new Gson().fromJson(json.toString(), JsonObject.class); + pageJson.addProperty("StartRow", startRow); + pageJson.addProperty("Limit", pageSize); + String resultJson = String.valueOf(client.billQuery(pageJson.toString())); + JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); + if (jsonArray == null || jsonArray.size() == 0) { + break; + } + List pageList = objectMapper.readValue( + jsonArray.toString(), new TypeReference>() { + }); + productionOrderDTOList.addAll(pageList); + if (jsonArray.size() < pageSize) { + break; + } + startRow += pageSize; + } + } catch (Exception e) { + e.printStackTrace(); // 输出异常日志 + } + + return productionOrderDTOList; // 返回结果 + } + + /** + * 待转序查询,工序转移单非委外列表 + * 不包含暂停状态的项目 + */ + public static List getProcessTransferForm() { + //TOdo: 创建实体类 + + K3CloudApi client = new K3CloudApi(); + // 请求参数,要求为json字符串 + JsonObject json = new JsonObject(); + json.addProperty("FormId", "SFC_OperationTransfer"); + json.addProperty("FieldKeys", "F_HBYT_SCLH,FProductId.FNumber,FBillNo,FMOBillNo,FDocumentStatus,FProductName,FOutDeptId.FName,FOutOperNumber,FOutProcessId.FName,FInDeptId.FName,FInOperNumber,FInProcessId.FName,FOperUnitId.FName,FOperTransferQty,FOperQualifiedQty,FOperProFailQty,FCreateDate"); + // 创建过滤条件 + JsonObject filterObject = new JsonObject(); + JsonArray filterString = new JsonArray(); + filterObject.addProperty("FieldName", "FDocumentStatus"); + filterObject.addProperty("Compare", "105"); + filterObject.addProperty("Value", "B"); + filterObject.addProperty("Left", ""); + filterObject.addProperty("Right", ""); + filterObject.addProperty("Logic", 1); + filterString.add(filterObject); + + JsonObject filterObject2 = new JsonObject(); + filterObject2.addProperty("FieldName", "FDocumentStatus"); + filterObject2.addProperty("Compare", "105"); + filterObject2.addProperty("Value", "A"); + filterObject2.addProperty("Left", ""); + filterObject2.addProperty("Right", ""); + filterObject2.addProperty("Logic", 1); + filterString.add(filterObject2); + json.add("FilterString", filterString); + json.addProperty("OrderString", ""); + json.addProperty("TopRowCount", 0); + json.addProperty("StartRow", 0); + json.addProperty("Limit", 10000); + json.addProperty("SubSystemId", ""); + List processTransferFormDTOList = new ArrayList<>(); + int pageSize = 10000; + int startRow = 0; + ObjectMapper objectMapper = new ObjectMapper(); + try { + while (true) { + JsonObject pageJson = new Gson().fromJson(json.toString(), JsonObject.class); + pageJson.addProperty("StartRow", startRow); + pageJson.addProperty("Limit", pageSize); + String resultJson = String.valueOf(client.billQuery(pageJson.toString())); + JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); + if (jsonArray == null || jsonArray.size() == 0) { + break; + } + List pageList = objectMapper.readValue( + jsonArray.toString(), new TypeReference>() { + }); + processTransferFormDTOList.addAll(pageList); + if (jsonArray.size() < pageSize) { + break; + } + startRow += pageSize; + } + } catch (Exception e) { + e.printStackTrace(); // 输出异常日志 + } + + return processTransferFormDTOList; // 返回结果 + } + + /** + * 质检检验单 ,数据用来判定是否质检 + */ + public static List getQMInspectBill() { + K3CloudApi client = new K3CloudApi(); + // 请求参数,要求为json字符串 + JsonObject json = new JsonObject(); + json.addProperty("FormId", "SFC_OperationTransfer"); + json.addProperty("FieldKeys", "F_UCHN_Text,FBillNo,FDocumentStatus,FMaterialId.FNumber,FMaterialName,FMaterialModel,FQCStatus,FInspectResult,FUnitID.FName,FInspectQty,FQualifiedQty,FUnqualifiedQty"); + // 创建过滤条件 + JsonObject filterObject = new JsonObject(); + JsonArray filterString = new JsonArray(); + //质检转态:计划1 质检开始2 质检状态3 :FQCStatus + filterObject.addProperty("FieldName", "FQCStatus"); + filterObject.addProperty("Compare", "29"); + filterObject.addProperty("Value", "1"); + filterObject.addProperty("Left", ""); + filterObject.addProperty("Right", ""); + filterObject.addProperty("Logic", 0); + filterString.add(filterObject); + + json.add("FilterString", filterString); + json.addProperty("OrderString", ""); + json.addProperty("TopRowCount", 0); + json.addProperty("StartRow", 0); + json.addProperty("Limit", 10000); + json.addProperty("SubSystemId", ""); + List inspectionSheetDTOList = new ArrayList<>(); + int pageSize = 10000; + int startRow = 0; + ObjectMapper objectMapper = new ObjectMapper(); + try { + while (true) { + JsonObject pageJson = new Gson().fromJson(json.toString(), JsonObject.class); + pageJson.addProperty("StartRow", startRow); + pageJson.addProperty("Limit", pageSize); + String resultJson = String.valueOf(client.billQuery(pageJson.toString())); + JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); + if (jsonArray == null || jsonArray.size() == 0) { + break; + } + List pageList = objectMapper.readValue(jsonArray.toString(), new TypeReference>() { + }); + inspectionSheetDTOList.addAll(pageList); + if (jsonArray.size() < pageSize) { + break; + } + startRow += pageSize; + } + } catch (Exception e) { + e.printStackTrace(); // 输出异常日志 + } + + return inspectionSheetDTOList; // 返回结果 + } + + /** + * 工序汇报单 用来查询是否入库 + * 判断条件是否入库点,合格数量和入库数量是否相同 + */ + public static List getProcessReport() { + K3CloudApi client = new K3CloudApi(); + // 请求参数,要求为json字符串 + JsonObject json = new JsonObject(); + json.addProperty("FormId", "SFC_OperationReport"); + json.addProperty("FieldKeys", "F_HBYT_SCLH,FBillNo,FMoNumber,FWorkShopID.FName,FOperNumber,FOperDescription,FQuaQty,FFinishQty,FStockInQuaAuxQty,FStockInFailAuxQty,F_HBYT_RKD,FDate"); + // 是否为入库点 + JsonObject filterObject = new JsonObject(); + JsonArray filterString = new JsonArray(); + filterObject.addProperty("FieldName", "F_HBYT_RKD"); + filterObject.addProperty("Compare", "74"); + filterObject.addProperty("Value", true); + filterObject.addProperty("Left", ""); + filterObject.addProperty("Right", ""); + filterObject.addProperty("Logic", 0); + filterString.add(filterObject); + JsonObject filterObject1 = new JsonObject(); + filterObject1.addProperty("FieldName", "FDocumentStatus"); + filterObject1.addProperty("Compare", "105"); + filterObject1.addProperty("Value", "A"); + filterObject1.addProperty("Left", ""); + filterObject1.addProperty("Right", ""); + filterObject1.addProperty("Logic", 1); + filterString.add(filterObject1); + JsonObject filterObject2 = new JsonObject(); + filterObject2.addProperty("FieldName", "FDocumentStatus"); + filterObject2.addProperty("Compare", "105"); + filterObject2.addProperty("Value", "B"); + filterObject2.addProperty("Left", ""); + filterObject2.addProperty("Right", ""); + filterObject2.addProperty("Logic", 1); + filterString.add(filterObject2); + json.add("FilterString", filterString); + json.addProperty("OrderString", ""); + json.addProperty("TopRowCount", 0); + json.addProperty("StartRow", 0); + json.addProperty("Limit", 10000); + json.addProperty("SubSystemId", ""); + List processReportDTOList = new ArrayList<>(); + int pageSize = 10000; + int startRow = 0; + ObjectMapper objectMapper = new ObjectMapper(); + try { + while (true) { + JsonObject pageJson = new Gson().fromJson(json.toString(), JsonObject.class); + pageJson.addProperty("StartRow", startRow); + pageJson.addProperty("Limit", pageSize); + String resultJson = String.valueOf(client.billQuery(pageJson.toString())); + JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); + if (jsonArray == null || jsonArray.size() == 0) { + break; + } + List pageList = objectMapper.readValue(jsonArray.toString(), new TypeReference>() { + }); + processReportDTOList.addAll(pageList); + if (jsonArray.size() < pageSize) { + break; + } + startRow += pageSize; + } + } catch (Exception e) { + e.printStackTrace(); // 输出异常日志 + } + + return processReportDTOList; // 返回结果 + } + + + /** + * 从金蝶获取质检看板数据 + */ + public static List getUninspectedData() { + List kingdeeWorkCenterDataVos = new ArrayList<>(); + try { + K3CloudApi client = new K3CloudApi(); + // 调用金蝶接口 + String execute = client.execute( + "Ljint.Kingdee.YiTe.KanBan.WebApi.QualityWebApi.ExecuteService,Ljint.Kingdee.YiTe.KanBan.WebApi", + new String[]{" "} + ); + // 解析返回结果 + JSONObject response = JSONObject.parseObject(execute); + if (response == null) { + log.error("金蝶接口返回为空!"); + return Collections.emptyList(); + } + if (!"true".equalsIgnoreCase(response.getString("IsSuccess"))) { + String errorMsg = response.getString("Message"); + log.error("金蝶接口调用失败:{}", errorMsg); + return Collections.emptyList(); + } + // 获取数据数组 + JSONArray dataArray = response.getJSONArray("data"); + if (dataArray == null || dataArray.isEmpty()) { + log.warn("金蝶接口返回的质检数据为空!"); + return Collections.emptyList(); + } + // 解析每个工段下的 QueryList + for (int i = 0; i < dataArray.size(); i++) { + JSONArray queryList = dataArray.getJSONObject(i).getJSONArray("QueryList"); + if (queryList == null || queryList.isEmpty()) { + continue; + } + for (int j = 0; j < queryList.size(); j++) { + JSONObject item = queryList.getJSONObject(j); + if (item == null) continue; + // 转换为实体对象 + ProcessInspectionDTO data = new ProcessInspectionDTO(); + data.setMoBillNo(item.getString("MoBillNo")); + data.setMoOrderNo(item.getString("MoOrderNo")); + data.setSubOrderNo(item.getString("SubOrderNo")); + data.setFMaterialName(item.getString("FMaterialName")); + data.setFProcessName(item.getString("FProcessName")); + data.setFWorkCenterName(item.getString("FWorkCenterName")); + data.setFInspectStatus(item.getString("FInspectStatus")); + data.setFWaitInspectQty(item.getInteger("FWaitInspectQty")); + data.setFFinishInspectQty(item.getInteger("FFinishInspectQty")); + data.setFQuaQty(item.getInteger("FQuaQty")); + data.setFReworkQty(item.getInteger("FReworkQty")); + data.setFFailQty(item.getInteger("FFailQty")); + data.setFSubmitInspectTime(item.getString("FSubmitInspectTime")); + data.setFFinishInspectTime(item.getString("FFinishInspectTime")); + data.setFDescription(item.getString("FDescription")); + kingdeeWorkCenterDataVos.add(data); + } + } + + } catch (Exception e) { + log.error("调用金蝶接口获取质检看板数据异常:{}", e.getMessage(), e); + return Collections.emptyList(); + } + return kingdeeWorkCenterDataVos; + } + + + /** + * 工序汇报单 用来查询是否入库 + * 判断条件是否入库点,合格数量和入库数量是否相同 + */ + public static OperationPlannDTO getOperationPlann(String FBillNo) { + K3CloudApi client = new K3CloudApi(); + // 请求参数,要求为json字符串 + JsonObject json = new JsonObject(); + json.addProperty("FormId", "SFC_OperationPlanning"); + json.addProperty("FieldKeys", "FOperNumber,FOperQty,FProcessId.FName"); + // 是否为入库点 + JsonObject filterObject = new JsonObject(); + JsonArray filterString = new JsonArray(); + filterObject.addProperty("FieldName", "FMONumber"); + filterObject.addProperty("Compare", "67"); + filterObject.addProperty("Value", FBillNo); + filterObject.addProperty("Left", ""); + filterObject.addProperty("Right", ""); + filterObject.addProperty("Logic", 0); + filterString.add(filterObject); + + JsonObject filterObjec1t = new JsonObject(); + filterObjec1t.addProperty("FieldName", "FOperStatus"); + filterObjec1t.addProperty("Compare", "105"); + filterObjec1t.addProperty("Value", "4"); + filterObjec1t.addProperty("Left", ""); + filterObjec1t.addProperty("Right", ""); + filterObjec1t.addProperty("Logic", 0); + filterString.add(filterObjec1t); + json.add("FilterString", filterString); + json.addProperty("OrderString", ""); + json.addProperty("TopRowCount", 0); + json.addProperty("StartRow", 0); + json.addProperty("Limit", 10000); + json.addProperty("SubSystemId", ""); + List processReportDTOList = new ArrayList<>(); + int pageSize = 10000; + int startRow = 0; + ObjectMapper objectMapper = new ObjectMapper(); + try { + while (true) { + JsonObject pageJson = new Gson().fromJson(json.toString(), JsonObject.class); + pageJson.addProperty("StartRow", startRow); + pageJson.addProperty("Limit", pageSize); + String resultJson = String.valueOf(client.billQuery(pageJson.toString())); + JsonArray jsonArray = new Gson().fromJson(resultJson, JsonArray.class); + if (jsonArray == null || jsonArray.size() == 0) { + break; + } + List pageList = objectMapper.readValue(jsonArray.toString(), + new TypeReference>() { + }); + if (pageList != null && !pageList.isEmpty()) { + processReportDTOList.addAll(pageList); + } + if (jsonArray.size() < pageSize) { + break; + } + startRow += pageSize; + } + } catch (Exception e) { + e.printStackTrace(); // 输出异常日志 + } + + if (processReportDTOList.isEmpty()) { + return null; + } + // 选择工序号最小的作为代表项(通常为最后一道工序) + OperationPlannDTO best = null; + int bestOper = Integer.MAX_VALUE; + for (OperationPlannDTO dto : processReportDTOList) { + int oper = Integer.MAX_VALUE; + try { + String numStr = dto.getFOperNumber(); + if (numStr != null) { + oper = Integer.parseInt(numStr.trim()); + } + } catch (Exception ignore) { + oper = Integer.MAX_VALUE; + } + if (oper <= bestOper) { + bestOper = oper; + best = dto; + } + } + return best; + } + + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/runner/PDFGenerator.java b/ruoyi-system/src/main/java/com/ruoyi/system/runner/PDFGenerator.java index 11a53c9..e33a6d7 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/runner/PDFGenerator.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/runner/PDFGenerator.java @@ -18,10 +18,9 @@ import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter; @@ -104,14 +103,24 @@ public class PDFGenerator { throw new RuntimeException("无法创建目录: " + directoryPath); } } else { - // 如果目录存在,删除其中的所有文件 - File[] files = directory.listFiles(); - if (files != null) { - for (File file : files) { - if (!file.delete()) { - System.err.println("无法删除文件: " + file.getAbsolutePath()); + // 目录存在:使用NIO递归清理目录内容(不删除根目录本身) + try { + Path root = Paths.get(directoryPath); + if (java.nio.file.Files.exists(root)) { + try (java.util.stream.Stream walk = java.nio.file.Files.walk(root)) { + walk.filter(p -> !p.equals(root)) + .sorted(java.util.Comparator.reverseOrder()) // 先删子路径再删父路径 + .forEach(p -> { + try { + java.nio.file.Files.deleteIfExists(p); + } catch (IOException e) { + System.err.println("删除失败: " + p.toString() + ": " + e.getMessage()); + } + }); } } + } catch (IOException e) { + throw new RuntimeException("清理目录失败: " + directoryPath + ", " + e.getMessage(), e); } } for (CombinedDTO combinedVo : combinedVoList) { @@ -125,10 +134,12 @@ public class PDFGenerator { String materialCode; Long fmoQty; String fDepartmentName; - // 获取第一序的工序名称 + String OrderNumber = ""; + // 获取第一序的工序名称 List processes = combinedVo.getProcesses(); if (!processes.isEmpty()) { fProcessName = processes.get(0).getFProcessName(); + OrderNumber = combinedVo.getOrderNumber(); productionOrderNumber = String.valueOf(combinedVo.getProcesses().get(0).getFBillNo()); starttime = combinedVo.getProcesses().get(0).getFPlanStartTime(); endtime = combinedVo.getProcesses().get(0).getFPlanFinishTime(); @@ -166,11 +177,11 @@ public class PDFGenerator { // 获取当前时间的毫秒时间戳 long timestamp = System.currentTimeMillis(); - String pdfPath = departmentFolder.getAbsolutePath() + "\\" + fDepartmentName + "_" - + materialCode1.replace("/", "_") + "_" + productionOrderNumber + ".pdf"; + String pdfPath = departmentFolder.getAbsolutePath() + "\\" + fDepartmentName + "_" + materialCode1.replace("/", "_") + "_" + productionOrderNumber + ".pdf"; + PDDocument document = null; try { // 创建 PDF 文件并写入内容 - PDDocument document = new PDDocument(); + document = new PDDocument(); PDPage page = new PDPage(); document.addPage(page); PDType0Font font = PDType0Font.load(document, new File(fontPath)); @@ -223,14 +234,15 @@ public class PDFGenerator { float[] processColWidths = { 35, 78, 35, 55, 45, 170, 55, 60, 60 }; yStart = processTableStartY; - drawTableRow(contentStream, font, margin, yStart, tableWidth, processColWidths, new String[] { + // 使用支持换行的方法绘制表头 + yStart = drawTableRowWithWrap(contentStream, font, margin, yStart, tableWidth, processColWidths, new String[] { "工序号", "工序名称", "数量", "工作中心", "工时(分)", "工序说明", "控制码", "开始时间", "结束时间" }, document, page, rowHeight, pageHeight); for (PlannedProcessVo process : combinedVo.getProcesses()) { SimpleDateFormat formatte1r = new SimpleDateFormat("yyyy-MM-dd"); - yStart -= rowHeight; - drawTableRow(contentStream, font, margin, yStart, tableWidth, processColWidths, new String[] { + // 使用支持换行的方法绘制数据行,特别是工序说明字段 + yStart = drawTableRowWithWrap(contentStream, font, margin, yStart, tableWidth, processColWidths, new String[] { String.valueOf(process.getFOperNumber()), process.getFProcessName(), String.valueOf(process.getFOperQty()), process.getFWorkCenterName(), String.format("%.2f", process.getFActivity1BaseQty()), @@ -309,6 +321,14 @@ public class PDFGenerator { pdfPaths.add(pdfPath); } catch (IOException | WriterException e) { e.printStackTrace(); + } finally { + if (document != null) { + try { + document.close(); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + } } } } @@ -478,4 +498,122 @@ public class PDFGenerator { } } + // ... 其他代码 ... + + // Java 8兼容的文本换行处理方法 + private static List wrapText(String text, PDType0Font font, float fontSize, float maxWidth) throws IOException { + List lines = new ArrayList(); + if (text == null || text.trim().isEmpty()) { + lines.add(""); + return lines; + } + + // 去除换行符,用空格替换 + text = text.replace("\n", " ").replace("\r", " ").trim(); + + // 增加边距,确保文本不会超出边界 + float effectiveWidth = maxWidth - 20; // 增加边距到20个单位 + + StringBuilder currentLine = new StringBuilder(); + + // 逐字符处理,更好地支持中文 + for (int i = 0; i < text.length(); i++) { + char currentChar = text.charAt(i); + String testLine = currentLine.toString() + currentChar; + + float textWidth = font.getStringWidth(testLine) / 1000 * fontSize; + + if (textWidth <= effectiveWidth) { + currentLine.append(currentChar); + } else { + // 当前行已满,开始新行 + if (currentLine.length() > 0) { + lines.add(currentLine.toString().trim()); + currentLine = new StringBuilder(); + currentLine.append(currentChar); + } else { + // 单个字符就超宽(极少见情况),强制添加 + lines.add(String.valueOf(currentChar)); + } + } + } + + // 添加最后一行 + if (currentLine.length() > 0) { + lines.add(currentLine.toString().trim()); + } + + // 如果没有任何内容,至少返回一个空行 + if (lines.isEmpty()) { + lines.add(""); + } + + return lines; + } + + // Java 8兼容的改进表格绘制方法,支持自动换行 + private static float drawTableRowWithWrap(PDPageContentStream contentStream, PDType0Font font, float margin, + float yStart, float tableWidth, float[] colWidths, String[] cells, PDDocument document, + PDPage page, float baseRowHeight, float pageHeight) throws IOException { + + float nextX = margin; + float nextY = yStart; + float fontSize = 10; + int maxColumns = Math.min(cells.length, colWidths.length); + + // 计算每列的文本行数,确定实际行高 + List> allCellLines = new ArrayList>(); + int maxLines = 1; + + for (int i = 0; i < maxColumns; i++) { + String cellText = cells[i] != null ? cells[i] : ""; + List lines = wrapText(cellText, font, fontSize, colWidths[i]); + allCellLines.add(lines); + maxLines = Math.max(maxLines, lines.size()); + } + + float actualRowHeight = baseRowHeight * maxLines; + + // 检查是否需要分页 + if (nextY - actualRowHeight < margin) { + contentStream.close(); + // 创建新页面 + page = new PDPage(); + document.addPage(page); + contentStream = new PDPageContentStream(document, page); + // 重置Y坐标为新页面顶部 + nextY = pageHeight - margin; + } + + // 绘制表格边框和内容 + nextX = margin; + for (int i = 0; i < maxColumns; i++) { + List lines = allCellLines.get(i); + + // 绘制单元格边框 + contentStream.moveTo(nextX, nextY); + contentStream.lineTo(nextX, nextY - actualRowHeight); + contentStream.lineTo(nextX + colWidths[i], nextY - actualRowHeight); + contentStream.lineTo(nextX + colWidths[i], nextY); + contentStream.closeAndStroke(); + + // 绘制文本内容 + for (int lineIndex = 0; lineIndex < lines.size(); lineIndex++) { + String line = lines.get(lineIndex); + if (!line.isEmpty()) { + contentStream.beginText(); + contentStream.setFont(font, fontSize); + float textY = nextY - 15 - (lineIndex * (fontSize + 2)); + contentStream.newLineAtOffset(nextX + 8, textY); // 增加左边距到8个单位 + contentStream.showText(line); + contentStream.endText(); + } + } + + nextX += colWidths[i]; + } + + return nextY - actualRowHeight; // 返回下一行的Y坐标 + } + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/runner/updatePcessPlanConver.java b/ruoyi-system/src/main/java/com/ruoyi/system/runner/updatePcessPlanConver.java index decf946..4b49deb 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/runner/updatePcessPlanConver.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/runner/updatePcessPlanConver.java @@ -70,7 +70,6 @@ public class updatePcessPlanConver { String formId = "SFC_OperationPlanning"; //调用接口 String resultJson = client.save(formId, jsonOutput); - System.out.println("调用接口:+++++" + jsonOutput); //用于记录结果 Gson gson = new Gson(); //对返回结果进行解析和校验 @@ -108,7 +107,6 @@ public class updatePcessPlanConver { //业务对象标识工序计划表 String formId = "SFC_OperationPlanning"; //调用接口 - System.out.println("调用接口:"+model.getFProcessId_number()+"+++++" + jsonOutput); String resultJson = client.save(formId, jsonOutput); //用于记录结果 Gson gson = new Gson(); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IPartCostService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IPartCostService.java new file mode 100644 index 0000000..dbbe25c --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IPartCostService.java @@ -0,0 +1,50 @@ +package com.ruoyi.system.service; + +import com.ruoyi.system.domain.vo.PartCostVo; +import com.ruoyi.system.domain.bo.PartCostBo; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 零件成本Service接口 + * + * @author 田志阳 + * @date 2025-10-24 + */ +public interface IPartCostService { + + /** + * 查询零件成本 + */ + PartCostVo queryById(Long id); + + /** + * 查询零件成本列表 + */ + TableDataInfo queryPageList(PartCostBo bo, PageQuery pageQuery); + + /** + * 查询零件成本列表 + */ + List queryList(PartCostBo bo); + + /** + * 新增零件成本 + */ + Boolean insertByBo(PartCostBo bo); + + /** + * 修改零件成本 + */ + Boolean updateByBo(PartCostBo bo); + + /** + * 校验并批量删除零件成本信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + boolean getObtainPartData(); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IProcessRouteService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IProcessRouteService.java index ae80c09..b9d1e3b 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IProcessRouteService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IProcessRouteService.java @@ -3,6 +3,7 @@ package com.ruoyi.system.service; import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.system.domain.dto.BOMItem; import com.ruoyi.system.domain.BomDetails; import com.ruoyi.system.domain.MaterialBom; import com.ruoyi.system.domain.ProcessRoute; @@ -84,7 +85,7 @@ public interface IProcessRouteService { * 推送工艺路线 */ - ProcessRoutePushResultDTO pushRouteBom(String rooteProdet); + R pushRouteBom(String rooteProdet); /** * 获取所有的项目令号 */ @@ -143,4 +144,9 @@ public interface IProcessRouteService { String getRouteCode(String materialCode,String code); List selectByProjectNumber(String productionOrderNo); + + R viewGetBomUploadStatus(String rooteProdet); + + //根据令号和物料编码 查询工艺路线 + ProcessRoute getProcessRoutesXuTime(String productionOrderNo, String materialCode,String xu); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BomDetailsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BomDetailsServiceImpl.java index 3adb968..35b12de 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BomDetailsServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BomDetailsServiceImpl.java @@ -107,6 +107,7 @@ public class BomDetailsServiceImpl implements IBomDetailsService { lqw.like(StringUtils.isNotBlank(bo.getFName()), BomDetails::getFName, bo.getFName()); lqw.eq(StringUtils.isNotBlank(bo.getStats()), BomDetails::getStats, bo.getStats()); lqw.eq(StringUtils.isNotBlank(bo.getWareHouse()), BomDetails::getWareHouse, bo.getWareHouse()); + lqw.eq(StringUtils.isNotBlank(bo.getBomType()), BomDetails::getBomType, bo.getBomType()); lqw.orderByAsc(BomDetails::getTotalWeight); return lqw; } @@ -222,11 +223,10 @@ public class BomDetailsServiceImpl implements IBomDetailsService { MaterialBom matchedMaterialBom = materialBomMap.get(key); if (matchedMaterialBom != null) { if (matchedMaterialBom.getUnit().equals("根")) { - bomDetail.setQuantity(Double.valueOf(String.valueOf(matchedMaterialBom.getQuantity()).split("/")[0])); + bomDetail.setQuantity(String.valueOf(matchedMaterialBom.getQuantity()).split("/")[0]); bomDetail.setDenominator(Double.valueOf(String.valueOf(matchedMaterialBom.getQuantity()).split("/")[1])); - } else { - bomDetail.setQuantity(Double.valueOf(String.valueOf(matchedMaterialBom.getQuantity()))); + bomDetail.setQuantity(String.valueOf(matchedMaterialBom.getQuantity())); } } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ImMaterialServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ImMaterialServiceImpl.java index d1569a2..c549c66 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ImMaterialServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ImMaterialServiceImpl.java @@ -179,21 +179,6 @@ public class ImMaterialServiceImpl implements IImMaterialService { try { LambdaQueryWrapper lqw = buildQueryWrapper(bo); - lqw.like(StringUtils.isNotBlank(bo.getMaterialCode()), ImMaterial::getMaterialCode, bo.getMaterialCode()); - lqw.like(StringUtils.isNotBlank(bo.getMaterialName()), ImMaterial::getMaterialName, bo.getMaterialName()); - lqw.like(StringUtils.isNotBlank(bo.getClassificationName()), ImMaterial::getClassificationName, bo.getClassificationName()); - lqw.like(StringUtils.isNotBlank(bo.getImCategory()), ImMaterial::getImCategory, bo.getImCategory()); - lqw.like(StringUtils.isNotBlank(bo.getMaterialQuality()), ImMaterial::getMaterialQuality, bo.getMaterialQuality()); - lqw.eq(bo.getSingleWeight() != null, ImMaterial::getSingleWeight, bo.getSingleWeight()); - lqw.eq( ImMaterial::getForbidStatus, "A"); - lqw.like(StringUtils.isNotBlank(bo.getUnit()), ImMaterial::getUnit, bo.getUnit()); - lqw.like(bo.getFlag() != null, ImMaterial::getFlag, bo.getFlag()); - lqw.orderBy(true, false, ImMaterial::getModifyDate); - - - System.out.println("+++++++++++++++++++++++++++++++++++++++"+lqw.getSqlSegment()); - - // 执行查询 Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); if (CollectionUtils.isEmpty(result.getRecords())) { return TableDataInfo.build(result); // 如果结果为空,直接返回 @@ -414,11 +399,10 @@ public class ImMaterialServiceImpl implements IImMaterialService { lqw.like(StringUtils.isNotBlank(bo.getImCategory()), ImMaterial::getImCategory, bo.getImCategory()); lqw.like(StringUtils.isNotBlank(bo.getMaterialQuality()), ImMaterial::getMaterialQuality, bo.getMaterialQuality()); lqw.eq(bo.getSingleWeight() != null, ImMaterial::getSingleWeight, bo.getSingleWeight()); - lqw.eq(bo.getForbidStatus() != null, ImMaterial::getForbidStatus, "否"); - lqw.like(bo.getUnitPrice() != null, ImMaterial::getUnitPrice, bo.getUnitPrice()); + lqw.eq( ImMaterial::getForbidStatus, "A"); lqw.like(StringUtils.isNotBlank(bo.getUnit()), ImMaterial::getUnit, bo.getUnit()); lqw.like(bo.getFlag() != null, ImMaterial::getFlag, bo.getFlag()); - lqw.orderBy(true, false, ImMaterial::getUnit); + lqw.orderBy(true, false, ImMaterial::getModifyDate); return lqw; } @@ -745,9 +729,11 @@ public class ImMaterialServiceImpl implements IImMaterialService { // 根据 materialId 查询是否存在 ImMaterial existing = baseMapper.selectByMid(imMaterial.getMaterialId()); if (imMaterial.getForbidStatus().equals("A")){ - imMaterial.setForbidStatus("否"); + imMaterial.setForbidStatus("A"); + imMaterial.setUpdateTime(new Date()); }else { - imMaterial.setForbidStatus("是"); + imMaterial.setForbidStatus("B"); + imMaterial.setUpdateTime(new Date()); } if (existing != null) { diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MaterialBomServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MaterialBomServiceImpl.java index d54227a..a780711 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MaterialBomServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MaterialBomServiceImpl.java @@ -145,7 +145,7 @@ public class MaterialBomServiceImpl implements IMaterialBomService { bomDetails.setName(bo.getMaterialName()); bomDetails.setName(bo.getMaterialName()); bomDetails.setDenominator(1.0); - bomDetails.setQuantity(Double.valueOf(bo.getQuantity())); + bomDetails.setQuantity(bo.getQuantity()); bomDetails.setStats("外购"); bomDetails.setMaterial(bo.getMaterialType()); int flag = bomDetailsMapper.insert(bomDetails); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/PartCostServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/PartCostServiceImpl.java new file mode 100644 index 0000000..55f9ccd --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/PartCostServiceImpl.java @@ -0,0 +1,166 @@ +package com.ruoyi.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.system.runner.JdUtil; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import com.ruoyi.system.domain.bo.PartCostBo; +import com.ruoyi.system.domain.vo.PartCostVo; +import com.ruoyi.system.domain.PartCost; +import com.ruoyi.system.mapper.PartCostMapper; +import com.ruoyi.system.service.IPartCostService; + +import java.math.BigDecimal; +import java.util.*; + +/** + * 零件成本Service业务层处理 + * + * @author 田志阳 + * @date 2025-10-24 + */ +@RequiredArgsConstructor +@Service +public class PartCostServiceImpl implements IPartCostService { + + private final PartCostMapper baseMapper; + + /** + * 查询零件成本 + */ + @Override + public PartCostVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 查询零件成本列表 + */ + @Override + public TableDataInfo queryPageList(PartCostBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询零件成本列表 + */ + @Override + public List queryList(PartCostBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(PartCostBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getMaterialCode()), PartCost::getMaterialCode, bo.getMaterialCode()); + lqw.like(StringUtils.isNotBlank(bo.getMaterialName()), PartCost::getMaterialName, bo.getMaterialName()); + lqw.eq(bo.getCostPrice() != null, PartCost::getCostPrice, bo.getCostPrice()); + lqw.eq(bo.getCreateDate() != null, PartCost::getCreateDate, bo.getCreateDate()); + lqw.eq(StringUtils.isNotBlank(bo.getWorkshop()), PartCost::getWorkshop, bo.getWorkshop()); + lqw.eq(StringUtils.isNotBlank(bo.getUnit()), PartCost::getUnit, bo.getUnit()); + lqw.eq(StringUtils.isNotBlank(bo.getWarehouse()), PartCost::getWarehouse, bo.getWarehouse()); + lqw.eq(StringUtils.isNotBlank(bo.getSpecificationModel()), PartCost::getSpecificationModel, bo.getSpecificationModel()); + return lqw; + } + + /** + * 新增零件成本 + */ + @Override + public Boolean insertByBo(PartCostBo bo) { + PartCost add = BeanUtil.toBean(bo, PartCost.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改零件成本 + */ + @Override + public Boolean updateByBo(PartCostBo bo) { + PartCost update = BeanUtil.toBean(bo, PartCost.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(PartCost entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除零件成本 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + public boolean getObtainPartData() { + List list = JdUtil.getObtainPartData(); + if (list == null || list.isEmpty()) { + return false; + } + + Map uniq = new LinkedHashMap<>(); + for (PartCost pc : list) { + if (pc == null) continue; + + String code = pc.getMaterialCode(); + String name = pc.getMaterialName(); + BigDecimal cost = pc.getCostPrice(); + + // 过滤无效数据 + if (StringUtils.isBlank(code) || StringUtils.isBlank(name) || cost == null || cost.compareTo(BigDecimal.ZERO) == 0) { + continue; + } + + // 以 物料编码 + 名称 为唯一键 + String key = code + "|" + name; + + PartCost existing = uniq.get(key); + // 保留 createDate 最新的 + if (existing == null || + (pc.getCreateDate() != null && + (existing.getCreateDate() == null || pc.getCreateDate().after(existing.getCreateDate())))) { + uniq.put(key, pc); + } + } + + List deduped = new ArrayList<>(uniq.values()); + if (deduped.isEmpty()) { + return false; + } + + // 删除旧记录 + for (PartCost pc : deduped) { + LambdaQueryWrapper delWrapper = Wrappers.lambdaQuery(); + delWrapper.eq(PartCost::getMaterialCode, pc.getMaterialCode()) + .eq(PartCost::getMaterialName, pc.getMaterialName()); + baseMapper.delete(delWrapper); + } + + // 批量插入最新记录 + return baseMapper.insertBatch(deduped); + } + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java index e75191d..334bc75 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java @@ -538,7 +538,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { log.info("出图接口响应=====>{}", response); // 2. 开始轮询状态接口,直到完成 boolean finished = false; - int maxRetry = 60; // 最多轮询 60 次(根据需求调整,比如 60*5s=5分钟) + int maxRetry = 360; // 最多轮询 60 次(根据需求调整,比如 60*5s=5分钟) int count = 0; while (!finished && count < maxRetry) { @@ -968,9 +968,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { FigureSave figureSave = figureSaveMapper.selectById(id); ProcessOrderPro processOrderPro = baseMapper.selectById(figureSave); if (figureSave == null) return "图纸信息不存在"; - String code = figureSave.getProductionCode(); - // 2. 拼接本地路径和FTP路径 String localPath = Constants.BASIC_URL; String ftpPath = ""; @@ -1252,7 +1250,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { 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) { diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessRouteServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessRouteServiceImpl.java index aaf0fe1..7e44f61 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessRouteServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessRouteServiceImpl.java @@ -19,11 +19,12 @@ 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.exception.ServiceException; +import com.ruoyi.system.domain.dto.BOMItem; +import com.ruoyi.system.domain.dto.BOMUploadResult; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.controller.ProcessRouteController; import com.ruoyi.system.domain.*; import com.ruoyi.system.domain.bo.MaterialBomBo; -import com.ruoyi.system.domain.bo.ProcessOrderProBo; import com.ruoyi.system.domain.bo.ProcessRouteBo; import com.ruoyi.system.domain.dto.*; import com.ruoyi.system.domain.vo.*; @@ -265,7 +266,6 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { } - /** * @param materialCode * @return @@ -291,8 +291,40 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { @Override public List selectByProjectNumber(String productionOrderNo) { LambdaQueryWrapper war = new LambdaQueryWrapper<>(); - war.eq(ProcessRoute::getRouteDescription,productionOrderNo); - return baseMapper.selectList(war); + war.eq(ProcessRoute::getRouteDescription, productionOrderNo); + return baseMapper.selectList(war); + } + + /** + * 获取bom的上传状态 + */ + @Override + public R viewGetBomUploadStatus(String rooteProdet) { + ProcessOrderPro processOrderPro = processOrderProMapper.selectByProjectNumber(rooteProdet); + String drawingType = processOrderPro.getDrawingType(); // 这里就是 JSON + // 转换 JSON 数组 -> List + List bomItems = JSONUtil.toList(drawingType, KindegeeLogDTO.class); + BOMItem result = new BOMItem(); + result.setItems(bomItems); + return R.ok(result); + } + + /** + * @param productionOrderNo + * @param materialCode + * @param xu + * @return + */ + @Override + public ProcessRoute getProcessRoutesXuTime(String productionOrderNo, String materialCode, String xu) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(ProcessRoute::getRouteDescription, productionOrderNo) + .eq(ProcessRoute::getMaterialCode, materialCode) + .eq(ProcessRoute::getProcessNo,xu); + if (baseMapper.selectOne(wrapper) != null) { + return baseMapper.selectOne(wrapper); + } + return null; } @@ -569,8 +601,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { saveBomDetails(bomDetailsVos); List routeArrayList = new ArrayList<>(); Map inventoryCache = new HashMap<>(); - - + // 批量查询所有需要的库存信息 boolean allEmpty = processRoutes.stream().allMatch(route -> route.getProcessNo() == null && route.getProcessName() == null); //获取工艺中所有的时间 挑选出最早的时间和最晚的时间 // 获取最早的开始时间 @@ -585,13 +616,13 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { .max(Comparator.comparing(ProcessRoute::getXuEndTime)) .map(ProcessRoute::getXuEndTime) .orElse(null); - //更新至计划模块中 + //更新至计划模块中 if (earliestStartTime != null && latestEndTime != null) { - ProcessOrderPro processOrderPro = processOrderProMapper.selectByProjectNumber(processRoutes.get(0).getRouteDescription()); + ProcessOrderPro processOrderPro = processOrderProMapper.selectByProjectNumber(processRoutes.get(0).getRouteDescription()); processOrderPro.setPlanStartTime(earliestStartTime); processOrderPro.setPlanEndTime(latestEndTime); processOrderPro.setUpdateTime(new Date()); - log.info("更新计划生成令号为:{},计划开始时间:{},计划结束时间:{}",processRoutes.get(0).getRouteDescription(), earliestStartTime, latestEndTime); + log.info("更新计划生成令号为:{},计划开始时间:{},计划结束时间:{}", processRoutes.get(0).getRouteDescription(), earliestStartTime, latestEndTime); processOrderProMapper.updateById(processOrderPro); } @@ -681,23 +712,42 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { } } } else { - for (ProcessRoute processRoute : processRoutes) { - if (processRoute.getProcessNo() != null - ||processRoute.getWorkCenter()!= null - ||processRoute.getProcessName() != null - ||processRoute.getMaterial().equals("总装部件")) { - processRoute.setActivityUnit("分"); - processRoute.setCreateTime(new Date()); - processRoute.setUpdateTime(new Date()); - processRoute.setBatchQuantity(processRoute.getBatchQuantity()); - processRoute.setUnitQuantity(processRoute.getUnitQuantity()); - routeArrayList.add(processRoute); - } + Date now = new Date(); + + // 先组装 routeArrayList + routeArrayList = processRoutes.stream() + .filter(pr -> pr.getProcessNo() != null + || pr.getWorkCenter() != null + || pr.getProcessName() != null) + .map(pr -> { + // 如果描述为空,则用工序控制码 + if (pr.getProcessDescription() == null || pr.getProcessDescription().isEmpty()) { + pr.setProcessDescription(pr.getProcessName()); + } + // 公共逻辑 + pr.setActivityUnit("分"); + pr.setCreateTime(now); + pr.setUpdateTime(now); + return pr; + }) + .collect(Collectors.toList()); + + // ✅ 校验是否存在相同物料编码 + 相同工序号 + Set duplicateKeys = routeArrayList.stream() + .map(pr -> pr.getMaterialCode() + "-" + pr.getProcessNo()) + .filter(Objects::nonNull) + .collect(Collectors.groupingBy(key -> key, Collectors.counting())) + .entrySet().stream() + .filter(e -> e.getValue() > 1) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + + if (!duplicateKeys.isEmpty()) { + log.error("发现重复的物料编码+工序号组合: {}", duplicateKeys); + throw new RuntimeException("存在重复的物料编码和工序号组合: " + duplicateKeys); } } - try { - return baseMapper.insertBatch(routeArrayList); } catch (Exception e) { log.error("批量插入工艺路线失败", e); @@ -733,10 +783,10 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { if ("mm".equals(unit)) { // 将毫米转换为米并保留4位小数 materialBom.setQuantity(String.valueOf(new BigDecimal(quantity).divide(BigDecimal.valueOf(1000), 4, RoundingMode.HALF_UP))); - } else if("根".equals(unit) && quantity.contains("/")){ + } else if ("根".equals(unit) && quantity.contains("/")) { //写入工艺表时分数的体现 直接取分母 以"/"为分割符,取第二个字符串 materialBom.setQuantity(quantity); - }else { + } else { // 其他单位直接使用原值,保留2位小数 materialBom.setQuantity(String.valueOf(new BigDecimal(quantity).setScale(2, RoundingMode.HALF_UP))); } @@ -777,6 +827,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { bomDetails.setPartdiagramName(productionOrderVo.getParentPart()); bomDetails.setPartNumber(productionOrderVo.getDrawingNo()); bomDetails.setName(productionOrderVo.getDrawingName()); + bomDetails.setBomType("0"); Double quantity = productionOrderVo.getQuantity(); bomDetails.setQuantity(quantity != null ? quantity : 0.0); @@ -830,6 +881,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { bomDetails.setFName(processRoute.getMaterialName()); bomDetails.setPartNumber(processRoute.getRawMaterialCode()); bomDetails.setName(processRoute.getRawMaterialName()); + bomDetails.setBomType("0"); // 添加单重验证和日志 Double discWeight = processRoute.getDiscWeight(); bomDetails.setDanZhong(discWeight); @@ -838,7 +890,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { // 处理单位换算 if ("mm".equals(processRoute.getBomUnit())) { - bomDetails.setQuantity(Double.parseDouble(processRoute.getDiscUsage())/ 1000.0); // 转换为米 + bomDetails.setQuantity(Double.parseDouble(processRoute.getDiscUsage()) / 1000.0); // 转换为米 bomDetails.setDenominator(1.0); // 转换为米 } else if ("根".equals(processRoute.getBomUnit())) { // 写入工艺表时分数的体现 直接取分母 以"/"为分割符,取第二个字符串 @@ -846,7 +898,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { String quanity2 = processRoute.getDiscUsage().split("/")[1]; bomDetails.setQuantity(Double.parseDouble(quanity)); bomDetails.setDenominator(Double.parseDouble(quanity2)); - bomDetails.setDenominator( Double.parseDouble(processRoute.getDiscUsage().split("/")[1])); + bomDetails.setDenominator(Double.parseDouble(processRoute.getDiscUsage().split("/")[1])); bomDetails.setQuantity(Double.parseDouble(processRoute.getDiscUsage().split("/")[0])); } else { bomDetails.setQuantity(Double.parseDouble(processRoute.getDiscUsage())); @@ -1072,12 +1124,12 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { // 验证物料是否存在 int materialVerification = isMaterialVerification(bomDetails.getPartNumber(), bomDetails.getName()); - if (materialVerification ==1) { + if (materialVerification == 1) { bomDetails.setUnitWeight("是"); - } else if(materialVerification ==2){ + } else if (materialVerification == 2) { bomDetails.setUnitWeight("否"); materialsToAdd.add(bomDetails); - }else if(materialVerification ==3){ + } else if (materialVerification == 3) { bomDetails.setUnitWeight("编码名称不符"); } @@ -1206,7 +1258,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { } @Override - public ProcessRoutePushResultDTO pushRouteBom(String rooteProdet) { + public R pushRouteBom(String rooteProdet) { List rawBomList = getProcessRoute(rooteProdet); List successfulRoutes = new ArrayList<>(); List failedRoutes = new ArrayList<>(); @@ -1217,6 +1269,14 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { Map> groupedByFNumber = jdProcessRoute.stream().collect(Collectors.groupingBy(ProcessRouteSelectDTO::getFNumber)); // 当前物料的工艺路线 List processRouteDT = processRouteXuDTO.getProcessRouteDT(); + /*boolean hasDuplicate = processRouteDT.stream() + .map(ProcessRouteDTO::getProcessNo) // 取出所有 processNo + .filter(Objects::nonNull) // 避免空指针 + .collect(Collectors.toSet()) // 放进 Set + .size() < processRouteDT.size(); + if (hasDuplicate){ + return R.fail("工序号重复请检查!"); + }*/ // 比较工艺路线 boolean isDifferent = compareProcessRoutes(processRouteDT, groupedByFNumber); if (isDifferent) { @@ -1229,6 +1289,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { successfulRoutes.add(processRouteXuDTO); } else { log.info("工艺路线保存失败: " + processRouteXuDTO.getMaterialCode() + result.getMessage()); + processRouteXuDTO.setErrorMessage( result.getMessage()); failedRoutes.add(processRouteXuDTO); } } else { @@ -1246,7 +1307,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { //更新项目状态 推送工艺 processOrderPro.setBomStatus(3L); processOrderProMapper.updateById(processOrderPro); - return resultDTO; + return R.ok(resultDTO); } public ProcessRoutePushResultDTO pushRouteQBBom(String rooteProdet) { @@ -1566,6 +1627,8 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { K3CloudApi client = new K3CloudApi(); ProcessModel processModel = createProcessModel(rawBomList); String jsonStr = JSONUtil.toJsonStr(processModel); + + log.debug("推送工艺报文=====》{}",JSONUtil.toJsonStr(jsonStr)); try { // 业务对象标识 String formId = "ENG_Route"; diff --git a/ruoyi-system/src/main/resources/EXCEL模板/工序汇报未入库.xlsx b/ruoyi-system/src/main/resources/EXCEL模板/工序汇报未入库.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..55c25e7444deb3656e6e68d0a917aaa5260bd5e5 GIT binary patch literal 10474 zcma)i1yo$g)-~?Z5G1&}ySr-Wqz~tmF>wdN5`LVX*u&<3}tW>#L z)YBs(C}An(s4Of9^R-|c=&!C_HcG)GvB5&n$+sQCci)FW)&zSvj39E89Qljm=@-3o7Jo?3IWHaS@o!JtiFM-K-7;k$Nee78$(JvGMm z`NrPXV?gx=j{x|>ijL%=-#Xo>rh+LS>>ax)GoIDqI7v~$NX~7`qq|$w)7dH-YVZBAs%aAK5_i z(nMMxH|zJ*IDXt(pF;kVT^nDuDdA^!4W8LW`8&IYKs)0Xdc$KzPHdBHQi; z6e=>tWQ8}1ZPlzkD=kHm>-wamB_W|Bnphs4oW6QEDydw+&JJi|Qp&-E z3Z839wlItjIpHxVZu3t0s?-F6)vS*fHMb5nd~U8iF|q)km9bGIG?Qqc8t-ryVRE_$ z32h+dbO1Qls0;^99#!h!_g{Il2xF-GnE1K|^5|KL6LXV55=8HGsqzWhAfQu@uWqnP zokq_2sT_?#w=mmM?`geq;_geUf+Xmk@U*jIWtWR(t>zc+&)BRR*|Kjlr*(9uK`I!A z%wGmOub~45#AtE@o2dI<_$Clxu&fM zSk4s;OR`74MKu|sYxuknhI+Od-r}-GhKs$=d!NxwMrNN(Pu>j_T=>>{kNy?&pM;BS zkZ({w6OQss_^W>q?r84-w0faDH(E!gixDmG81hM^-!mn$tOn1j?+$V^z}LP`Y0`m) zRZ41d5Af84Wgm*Uy8CsbnV0vNYj0mAY`wh(D{h$ZlnFwcc?Qugu_Iq@s|WCUX|N10 zejAI|4qWZ_Qspjlrn?5O9u$d44(fVVUdA6`$$kQRtu%M(Li*!uqvCPY{tus1=}HY7 zGn5`qVM}&ZSm0e}2Mf@(!b{94H0}GalYMHcb^3?S$V^P9UFI9r0ArN^&I{ADIQ)*B zlNiE=Q=2d*I@1NxgF8ImJ+wSPziRz{-PhSlBquI;hTi?=kStT7!FqE2N=i7~DMl%q zmON0aO~)!1a#FFiQ#2jcM=CUJ|0DckoiXe8wV#42m+T(8A~&Pl{O^tm`4M3dy{d)s zEz-P_yg**4{dYkDf2P*O@~4#iy8+TK181O}g}te;JO- z31NDfta#NW>ug4V=R30}(AyS3EUQ^jR8b0Ri_DB}hK>!Ya(l_4|JAXxr3i?h!W?oX zRz}0k@O)CwjC(St#Gu%46^OpGKW=gWZD_TQ_lJk&R2@PI$rv$GeJsRrX!Kq4+smOW zy?eRuRPjja{i5DiN;`?^6rFr>AvPNFEb|M@>8P+79^XPz-=do3vYy^gnC|D2jz(45 z3-3=4uv;!f&BK0pQ9b1qw?cAtq5)WHQ0F3KySSx3Wj3=dLb zLu@2TeBCD`m6;Po{i3~#&};*22sY4D%w64Zz{#}mxaAcmoC{uKq7yYdlsvohBWI0c z^;Hszp!QMgT}3;=7bP*)0*@0z9lViLW0eBC@TO1@_o{hS1BJOdAYrd_yR=*7x*;!G zw;k1wF7wzOy$s!dy`o_#=$a69TvDHXYRy1Y8v_40FGOxDp0OKEUIAM)2<%6-0c(@T zE)JEDmtGyQ4Fl)3>l^V&Rftu)>&r#SK1$qY#LT^0?ipb!;HRI_FPj;|G2|{l3YzZd z(k|vOgl+=w$auC%+}E*#o+e^H#M>FYVWi_5_Cy$WXphU`K#b!DhWin$wQ^Zos}9%lQ8o!7hqWubC((%=dFmI#30 zV!N)XQ!yQu45>zwvhddGeRK_aP8wVn{SDgv-rKj1TcYyQ0-&uBZ*2OeAK5_SV7ROFd|F+rizx#o30|^4s`n=>{)cHSVKaGDb_(P46NE|k_Hj-0;u$|Q-(vd!=8Oxg6 zePQP%mDt+-38~aDoG}+8o~9AR8VOQTQ6cT9dRsxkT-8mb$K(KFN~I^r^uvK}dE6`v z|4egvmh?6E4+L%3_t7+J1f;B-J=%Z-_Rh&3N(38jBa#?-?2W?@*PYg{VL~QRvS@q4 zZ6d^69G@Pp%QE?}wjiJhGeY^MVGOCNThj2D{Pjucs}S-}tcG2DNt@3GMuW3i##6@A z?9gVMP(>#hB^ANUkJB$Y9|A^^AbSeY%=IK)-7=;s4lRs)(OTya*$79h`P~ z3XTPZ1`A7ot)JtyG5Q#f_azZtu|a4y=3xIFeIk5Vo-rRq212M5O}u%olfv#C2=$z8 znp^&CA^IIF2x8EBUS-cjgI4*MWUg7TB#FqQQR{|f$CHFd84Gsjp%K4=@9S*+yX7St z2Q%-RHaFS&*NZJ~WE5%4RdFA%jZSLVJn}WoRCthd{S2fh_prG`2W#ZnBrv0xvV(M8 zTHfyCf3d$og|wtB$jy6Qt?U+(kohCbd81fZkyHx1-!-t$6y}Q+ku+2)goF{Q3>)-f zSO1-LV4#7Oq#R~25k-=vKf!w#IQ_!Qne$^^J}>NMx5w@Kjq39tfph^khsP7>>>(6h z(YwpCA z>(ID}mM$5j>JS_!8a5xv)>DweEV%Gb=3;mIf;mwsp;qu`@UVE=aqLAs>&cz`oP$K3 zPC&~?j(BRX4ESTaSHnZ?BifUmT3{-GkiA>)8!iQ0BDo6g^*XE(%}ZThiQC|C=UYw25bh6!x!buSvIMoYaN&`ZG$A-R z=D(vLU0G}%K{#G?BH>-{*5VDK8F71cylN=t^B?FG1KQS6yMMYU|SwAD(=D>84LU`gkE7nSJDPbsPty8bjWd1 z8<7*wv7!j|Lf|5Ig%?djbIVvq^zFE46scvKGWqbwbo#qBhVU2CD<=$x*k|h+X2pQY z!29Wu0NSrUqa+-NjSC00CCWW1ZocL{{gppPrIL3@g<&o!-#u}NOs%Qv%u zaz>*T)@KyeAi?eOLBNki*d(2P4>oiw zyWR_?=<;&ILpk&Ui89TpsAtfEBt+X!+ps~?rs1{KRA^i;8A5Pv$d6I6t_|Wk;=2+e z0!%STM07qGh!|s%@3E@S`WEY|eJQs{x8=}8q*hDD%D7e?b#XW>QbOz&7_5baOMje zn}GQ$#(Dc3^keQ=4*8`drmFjeXu?@xb06p`S_C5E%=H}#58~8c$B0iD$G@LKfsE<1 zGzye)TN$({`=rIQGhDGtOH)X<_X&My!+>d}(`l$kELi`tu9P_yVzJ#NOq}yth|OjT zoc2_PfOw{~nZMqmd7>zu-U-YpP7SO!b(l#`qZua0c+qZ}&1!?trUS9uVzKtHPny&m zzJ|v3$AJ~-yh2XVd;?mG#rY`YwyFla$X3tQn`*JAQoSe0cBt#mLti!q9mR7Q@dW*@ zo*@3Yjb}5F7u0#)!gD}_fV`YlpMNOqP4(@Jjov!gnOU3IzibU_RE{mC1YbYW-w617 z)S2bWVp#>2p#?R*E4|^88T+bkhj~n&TYcfzxvO9izbK!&u8>ctNrU!n@u2?Ax4{)|nwsR=-KdpBsBCm3if7QR2E-&Z%xh=HSBv5F&{xa-do@D1!U+y~gUi52st=A{G;gP89TeY~ z=6V}>mozrJDO(I*(|7M>f(g;Eb25>RPl%=9WOSnwTxPkfR}U~P0Y znk?rw7d0`bN8Ecd*@~WeH-_bQUJ6w{d%JVJ`hLsghYEc@k3UGa(m2@dJ=NRW^1+BP z(Nm9u6~gNHcqo+Q&V?A$E81&EqOjeG+qd^MM8HoBoVujMjYnE(nKC_lQ~jE~?7 z9XpfbbGYEbc;AfJ&neC8fvb=vm=ZE2pdKqGp=D&zQ2`rF$OhIGi*Qg}E$L9dZ`5Z@ z#%dZNqSc6EQ)C++QvJ1`CG_UBuDb6D25kltm|n@vZEg_K+MhM$IraEZq> z;Ao=Lsn;7xq7{^^7S$k&RmKwV7KPPDp^&okRI}q=Rk*fF&;xMk>{L5jr$8neKjg$G zU1%F9E9K5%O+^K8GM1UH(=m2PrtjZ$OWX6nYZJuoQV+$lM$DLuWhw$~53&MJWmyS) z@ZhaPk$np-><551weGQVn%zqg>7@?o3qdv4c?DcUTrAM88Lo6983~ijo-zH&7@X(Y zUhh$CW|5`qFw#ijPa|EJ!&mfnc(%G_QY$&^(>PnPcw$vhW%*r-n=VOj7lzzw!){e( zJ}jZj8k~iCQqH@HFwL!GJqZwXX{3*NLqp2!eyXpzr zgMF;t-)G%O0N`?6zhDJrKrq_`%!vKG{*_#pE@&%p>G15p`XQG==#h$&iH9Syc#U_@ z%lZQTpQ4m5U0X)#y-XDH2Bw%S&R@>ou1zw7=n)i$~I- zTUVL0L=oEOUdkJONp07|$5I93IfELOOU&l=J~tY75r#=1w3 zUOj=WaoKaNRgP&pZ4Ft9T@h`a-X66bFOQwx<@%-5tuU^9{(6xDd27%>nDkIPRe9$= z(s^CJ*CQ^3?Izx4I4{3uiGehtzcJZ6*H+7afn;^Q-)iQDTCt0q65u(8QxY%Tb=A7S z5{Q}Rvk(Mqj96mfz1cmA4+NiMq0 zYDKW~m(E@{ujwiGRRwdN?AAHjf(e>|r=1z3<~aBmpu^CfH}+gEPztlvb3^#H@dD2E z(H6z)ZpVV8&pmhdNkYcsTca{%Ko;XWDnwa=t#3GrR@l0(_ZTKd+sc?kIo;zilc&@SW!Rb_QWvCg;FF3vd;zqB{>jq zCPm3n%z0|Jr13NHvSimT!qfK>UlTm++)lZFnQq-cB9ijx43%D;K!cUOq6MLK)i^Ug ziHWmI&KYQWO5**%*!nQBy~48<>BVuoj?^FViZ(9VdSu|+F{yeN6CTPrgtgtZQwpRG zLzjRK#eVKxsAl?6A({^&U_P^Chm5gQ zHbZQGSjX0IG5sR1JhmfVVyC?mIRzpYO9A5!Egfh)dP~-vMR&uwv=8SLSSr9LzGnmC zmKjh0oUI$Ompem)cf13p)5`^~ot5yYXeBW9yh8AM%-~(CAcL9G97i2ygGUXRDf(DP z3p1zf!@z8gQqc~ZusXmc1`WZIVAk9q{h=ts39dKVq@e9vcifZ{f0&uGC5(>hP;GWJ z+y%%z2hIVb`I&58dDooMiN~Q0h|WAe!ii+ODsfz4?zQ%of~sjsTDacsylRkX)jJ~3@q7rhRN1b>yw(9<4@4!Vfp44j zt}6E8?dPjz4PHx4HLiwt*xi}Yp{3c!UVQ~;2JRYSCPn5sHaUy_8u9GUh3KxgXT^l? zidnxTgPF%+BF0udw0GT`69(iB$&FVedFsDQzyr^F%|gPo0)_J2^S&o>vQ+eVblJ$W!Pc6>didO^?cNzkux&bq?`rqH0y+4#CLs3tbj-8o}^FSGza8y^!i|tp)&LCqD z0oo>Yesymg(LN<*^Hqh$uBvludIDYO6~@=c=XANy zVtDH6ZPeFte|Y|h&_T>Q(6Fka$U-EL^CIaIat3Dtx1LrMfpZRyjp&hI;WWSuG7_S+B@JWVf0Hp(Ch~342!J6lRYBh}EaTP^3<&Um zn~M21oX^ z8fp2P*g^$HsBx2t>MI>(IWYR##==UR4BS~xNcb9-u`0`&_aKO9FcN&s=8Nl0`O;al zi1_D)q~F^=5=tq2dP}G1F0>e7pGn3_&NYK7k%}|cjtLt-KC8r%+C?@e)*qknI#K&P zRg13Sid#+7ms$T>X4Gn^YlFE?F4EUFX{{F8OzJ-Q=`QBx64&(QUkTneE96<`=SvZT zKF6bLyYYu5eB9IfT0Zrm=gaHFTPyddg!t!|l$+=-qh?EfHN(IqKa$q7+I;`SuMc8w zU-;k9<8wZoH9L&+9dPrV%2nJ)`VRD1@m4{Kz>AqZIi$VYy7KSwm*UiBqdA%ni-6v{bjf5zN+L-kMcanAF z_1;zX*&AUqYKgs!c|;BxNb8ds5!RgSp_~bO)TzmcC(j?-tJMQQfqy<^>sbW8Jpi*?V~V@x&US_uPs6zrWz@yUYf#x@xJ}3VoANE^)xcsc z@?$Tw$>>$otn+f7Pm^e6u3Wb#kwlPbRbr&V*8~D?AcJz&{F}KGA@_998Os+3-2g}pl%0!h0%vj#0py+uDI`(i?&+J2sRCYP*m^dp_3+bt2}M_Y z#83bt1&7z^{lHeRf1fXLcjwK=u?T@yF?taqxH$SU);ELXs4Jsgk%hBJ^BQ zc3xGzbwWlJIg_p}Xtygc_8JFv-aKkyS=ix_Go=k56%;U;7Sfa*$Jeajo{Qesi-X9Ny@ zLlK|>tVEQ}BA}0U*^#2%^5?tN6?;nUR$F!Y|sC>&Pcu>P-lwzJPQ^c04()E25 z7&3$cyzhtiNEDB=>{#&vi~wcY<1nq4pE~PtEpgo+ii{V3eiN?+v6tJ(3?I%Mi zdWSAyGO$$b5@LjS(ZpwWz{9tRJyO`^Qe@~99(}0uvDFe|{v3VIzqo;Bj$>*2f*N7d zcT%kcCqhDl4gUKAL#b$PWxrk)x6h^bNlyNuuREz8FWB5Xx_5CGj{tb`80Q%9mATRPh}8v>jo~l^d(J>K{&aSHjDWd1|F{{ZJlHK1Seg z4IX##-RJ$_`*vBtiC5i=evPZ1+?Bfr;3{*NvkTH4s+8cXUlbS*L>k$Gu{6x%#Z&8v z&j%AsD^9mS9F~N_10$Whk(P_T)v*u{YQgPh!-qi4?Xo3{J*BOXE-jnEE)}oLJ6IB{ zQ7J^{coyb@L(9Rt+GSH^trRJrG{iWsLaMik(4De5+uiNGuFMu5`P#5=@5j%2_rwEq z@D4}!KfONuyx??)N2KG{4J$3))cx_~BL)H$>yEA49avAC11d>`jo$a9M&re_q24kx zWD;A4ebV?{=s-T-cXKc-f$~dnuhFr1#cN(qJMZ{7yTXtd+`PkXz)&XU(Q>qMmrx50 zKU2*vP#rc`EVi~1Nt;|;T%E0{QnGG=T_+Wot8^kPHu)hHR;4<5pK<8D0$bI{{$(SG zWjS*bk$SxNyH2$?zc%^x_6>=n0uC))I3;3s#;b)Jg8w^V0QG#9dS_>B`FoDgoztoL z>G`v@=RnYNn(z-B`WMU6m@(;YMnLbe?=fJfRn8e5Wx;`g_`95ur}rn>r*ZOEF&c-h zEkcU4(~Z!PNw+&GYaT{TI4gv@OnDK_zK)8%g1~;KR>cz!7xfii$&!{Ca93rUPKc)c zGlL)gemlHzi}a+?Ivz^n%t1Ui0W3<`>C%+8U2=-630 zsHF5g9io_az^AvN%U`wIY-yAFwB-px$udW71*fLIb#_EgXnh%yP-ltgB`i(t1Gu5vL(#H0YU(wTCPVVmsZ9&gBfI} zq02L=r2)Hg6)neT9<1fgZwP~H>fB)P(Pbqoih;mdAgAeQV*h2dsMBdqJ5!$t)c_|h z8#+kdqJ2VPtYV7a(F?nZdAZQjCg}!1^qdw?kO^5Pil<||#afOV)ZuTz=?tQh zn`Zss!Q%Ny8XXz*%q0Cor`N^3JZa;t_Jd10O0+|Bdh8aRHXlfMOAQk2_=_zNW|9%s zi17M}&O)}-iMgC37|*`<&9wdVh+lB3X>alz=s|o=QoSUov_yc`4#w6F@049_jO}$^ zf<2{iL-JruXo1({tz9`%>7Q&2vzs7)ne{$i>yK@b~W21R+iwnQ-Ahm?pMQ6T-vNQPj;?uI_Q_Re4v zEVeF@1sOX*V@LL8(8f{};xe5$P4c^JA3%uG5+sIgCjIKD0QY0dW%Ml6~oe4#de&-);W&`DjJg7pluaxWm!)Z*;VZ|6z5laDS1jK{8L+gclx^myz@z#dok9F@h^WAe~0~1n)Ul=e=j!r3mx$MmHv;@ zKTD5(hyPwW^B4T;Suy^C|EG}Ve?9bbp!ARS^3aM9Kjr3s0shI-KGEOw>Gy&DE@Ur` zezAl?{5RNt$=dJz{GMd^tDlzV@|Ax}IsD$k?-9YjdQf^+kCz_)6CeEle|9UFpU^+^ z=l}eM{GLJo%VXT%VSnY*e;@Miq3pjpkbN#tdmi%NY5QM;eyQ;J)m~=U?$-?equ%GA lBmceP=LP#~*3$nA`&a#sf(+!(#ftJ=J_r45H$wV?`+tG{RagK3 literal 0 HcmV?d00001 diff --git a/ruoyi-system/src/main/resources/EXCEL模板/工序转移数据.xlsx b/ruoyi-system/src/main/resources/EXCEL模板/工序转移数据.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2aa858b419bc773feb6ef2435f0a1593c7773a31 GIT binary patch literal 9968 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 literal 0 HcmV?d00001 diff --git a/ruoyi-system/src/main/resources/EXCEL模板/生产开工未领料模板.xlsx b/ruoyi-system/src/main/resources/EXCEL模板/生产开工未领料模板.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e2a47cabe57110bcd7f5cb7cc936dc8a41cc6118 GIT binary patch literal 10745 zcma)iWmp}{wk_^13GVI-cZcA?J-FM#o!}bWCAd2wxVvkRpuyc8f;~viIeYKibMN=+ zM|Xd#rc{qwHM?rgAukOM0SEHhg5}l)U+@2JurCirKtp+ZpsfR={EHaI%MUQW#A-9H zh50~1K)As`Kv4cJrf+M@;A(A^9y2P{Er=0#<9EU|(w1HmA|Y7-LvoCu?!+f&v*2q) zF`_MUz|%05zKR@Du>_X`oU$P7mIO;Jp>^3A?gQIhQzx#ny4)`}eN7R4_Uk+a5Kux0A320KJhx*v&4d*7DXkoHY2$ zTzr(rESwf3#<RYE zBzj%mmGPB|huCPhcDGVvo`qQp|C@cEx22sWS!<_#G;0$2P&NV)fxQAg9@eX=*`3z5 z{0tR4jL5@<&AoS9j6*+d+E4nSt{?Xv(EkZ_sjH*3#0%60FHocY9cn|Mz40s7fw99D z-ApKAH-S(7lRsiMc~jvQvyrPUvL@maj{{gGMd>soEbyPbjCUpj-ZXt~R5LwB7&7Jg zK(4#mQX=cS>yrf$UX;�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 JCGuCj{|C_X+E@Sp literal 0 HcmV?d00001 diff --git a/ruoyi-system/src/main/resources/EXCEL模板/采购订单模板1.xlsx b/ruoyi-system/src/main/resources/EXCEL模板/采购订单模板1.xlsx index 45fe0f5b60b5eb789079e7fba91a29209e6d8eab..c0becc7ebc995d592e9188f3b1863bf669e5ae8a 100644 GIT binary patch delta 6905 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 delta 6801 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 QDP4F6Hz^t$`(MNV0JqYw>;M1& diff --git a/ruoyi-system/src/main/resources/mapper/system/BomDetailsMapper.xml b/ruoyi-system/src/main/resources/mapper/system/BomDetailsMapper.xml index 2cf6d83..1893072 100644 --- a/ruoyi-system/src/main/resources/mapper/system/BomDetailsMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/BomDetailsMapper.xml @@ -26,6 +26,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + diff --git a/ruoyi-system/src/main/resources/mapper/system/PartCostMapper.xml b/ruoyi-system/src/main/resources/mapper/system/PartCostMapper.xml new file mode 100644 index 0000000..29688f7 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/PartCostMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-system/src/main/resources/mapper/system/ProcessOrderProMapper.xml b/ruoyi-system/src/main/resources/mapper/system/ProcessOrderProMapper.xml index 16c75ec..a9479ed 100644 --- a/ruoyi-system/src/main/resources/mapper/system/ProcessOrderProMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/ProcessOrderProMapper.xml @@ -27,7 +27,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"