From fe1b02a121c173e9b2d56bbe5a1982e0e69e0548 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期二, 28 四月 2026 18:06:08 +0800
Subject: [PATCH] feat(production): 新增生产工单管理功能 - 创建 ProductionOperationTask 实体类定义工单数据结构 - 实现 ProductionOperationTaskController 提供工单的增删改查接口 - 开发 ProductionOperationTaskService 和实现类处理业务逻辑 - 配置 ProductionOperationTaskMapper 及 XML 文件实现数据库操作 - 添加 ProductionOperationTaskVo 视图对象用于数据展示 - 扩展 ProductionOrder 实体类增加生产订单相关属性 - 更新 ProductionOrderMapper.xml 完善订单查询映射配置 - 优化 ProductionOrderPickRecordMapper.xml 记录物料领取明细 - 新增 ProductionOrderRoutingOperationParam 参数配置实体 - 完善 工序参数处理逻辑

---
 src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java |  138 +++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 123 insertions(+), 15 deletions(-)

diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
index c148955..abbc525 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -40,8 +40,10 @@
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 @Service
@@ -63,7 +65,10 @@
     private final ProductionAccountMapper productionAccountMapper;
     private final ProductionOperationTaskMapper productionOperationTaskMapper;
     private final ProductionOrderMapper productionOrderMapper;
+    private final ProductionOrderBomMapper productionOrderBomMapper;
+    private final ProductionBomStructureMapper productionBomStructureMapper;
     private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
+    private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
     private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
     private final TechnologyOperationMapper technologyOperationMapper;
     private final StockUtils stockUtils;
@@ -87,7 +92,8 @@
 
     @Override
     public Boolean addProductMain(ProductionProductMainDto dto) {
-        if (dto.getProductionOperationTaskId() == null) {
+        Long taskId = resolveTaskId(dto);
+        if (taskId == null) {
             throw new ServiceException("璇蜂紶鍏ョ敓浜у伐鍗旾D");
         }
         return addProductMainByProductionTask(dto);
@@ -109,12 +115,16 @@
 
     private Boolean addProductMainByProductionTask(ProductionProductMainDto dto) {
         // 鎶ュ伐浠ヨ鍗曞伐搴忓揩鐓т负鍑嗭紝閬垮厤宸ヨ壓涓绘暟鎹彉鏇村悗褰卞搷鍘嗗彶宸ュ崟鎵ц銆�
+        Long taskId = resolveTaskId(dto);
+        if (taskId == null) {
+            throw new ServiceException("productionOperationTaskId can not be null");
+        }
         SysUser user = userMapper.selectUserById(dto.getUserId());
-        ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectById(dto.getProductionOperationTaskId());
+        ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectById(taskId);
         if (productionOperationTask == null) {
             throw new ServiceException("鐢熶骇宸ュ崟涓嶅瓨鍦�");
         }
-        ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOperationTask.getTechnologyRoutingOperationId());
+        ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOperationTask.getProductionOrderRoutingOperationId());
         if (routingOperation == null) {
             throw new ServiceException("璁㈠崟宸ヨ壓璺嚎宸ュ簭涓嶅瓨鍦�");
         }
@@ -122,6 +132,7 @@
         if (productionOrder == null) {
             throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
         }
+        syncOperationParamInputValue(dto, routingOperation.getId());
         TechnologyRoutingOperation technologyRoutingOperation = technologyRoutingOperationMapper.selectById(routingOperation.getTechnologyRoutingOperationId());
         TechnologyOperation technologyOperation = technologyRoutingOperation == null ? null
                 : technologyOperationMapper.selectById(technologyRoutingOperation.getTechnologyOperationId());
@@ -133,18 +144,17 @@
 
         ProductionProductMain productionProductMain = new ProductionProductMain();
         productionProductMain.setProductNo(generateProductNo());
-        productionProductMain.setUserId(dto.getUserId());
-        productionProductMain.setUserName(dto.getUserName());
-        productionProductMain.setProductionOperationTaskId(productionOperationTask.getId());
-        productionProductMain.setWorkOrderId(productionOperationTask.getId());
+        productionProductMain.setUserId(user == null ? dto.getUserId() : user.getUserId());
+        productionProductMain.setUserName(user == null ? dto.getUserName() : user.getNickName());
+        productionProductMain.setProductionOperationTaskId(taskId);
         productionProductMain.setStatus(0);
         productionProductMainMapper.insert(productionProductMain);
 
-        List<ProductStructureDto> productStructureDtos = new ArrayList<>();
-        ProductStructureDto productStructureDto = new ProductStructureDto();
-        productStructureDto.setProductModelId(productModel.getId());
-        productStructureDto.setUnitQuantity(BigDecimal.ONE);
-        productStructureDtos.add(productStructureDto);
+        List<ProductStructureDto> productStructureDtos = resolveInputStructures(
+                productionOrder.getId(), routingOperation, productModel.getId());
+        if (productStructureDtos.isEmpty()) {
+            throw new ServiceException("鏈壘鍒板綋鍓嶅伐搴忓搴旂殑BOM鎶曞叆鑺傜偣");
+        }
         for (ProductStructureDto item : productStructureDtos) {
             // 褰撳墠瀹炵幇鎸夊伐搴忔垚鍝佺洿鎺ヤ綔涓烘姇鍏ワ紝鍚庣画鑻ユ帴鍏ラ鏂欒褰曞彲鍦ㄨ繖閲屾浛鎹㈡潵婧愩��
             ProductionProductInput productionProductInput = new ProductionProductInput();
@@ -154,8 +164,6 @@
             productionProductInput.setInputQuantity(item.getUnitQuantity().multiply(defaultDecimal(dto.getQuantity())));
             productionProductInput.setQuantity(productionProductInput.getInputQuantity());
             productionProductInputMapper.insert(productionProductInput);
-            stockUtils.substractStock(item.getProductModelId(), productionProductInput.getInputQuantity(),
-                    StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode(), productionProductMain.getId());
         }
 
         ProductionProductOutput productionProductOutput = new ProductionProductOutput();
@@ -262,6 +270,99 @@
         return true;
     }
 
+    private void syncOperationParamInputValue(ProductionProductMainDto dto, Long productionOrderRoutingOperationId) {
+        if (dto == null || productionOrderRoutingOperationId == null) {
+            return;
+        }
+        List<ProductionOrderRoutingOperationParam> paramList = dto.getProductionOperationParamList();
+        if (paramList == null || paramList.isEmpty()) {
+            return;
+        }
+        List<ProductionOrderRoutingOperationParam> dbParamList = productionOrderRoutingOperationParamMapper.selectList(
+                Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
+                        .eq(ProductionOrderRoutingOperationParam::getProductionOrderRoutingOperationId, productionOrderRoutingOperationId));
+        if (dbParamList == null || dbParamList.isEmpty()) {
+            return;
+        }
+        Map<Long, ProductionOrderRoutingOperationParam> dbParamMap = dbParamList.stream()
+                .filter(item -> item != null && item.getId() != null)
+                .collect(Collectors.toMap(ProductionOrderRoutingOperationParam::getId, item -> item, (left, right) -> left));
+        for (ProductionOrderRoutingOperationParam param : paramList) {
+            if (param == null || param.getId() == null) {
+                continue;
+            }
+            ProductionOrderRoutingOperationParam dbParam = dbParamMap.get(param.getId());
+            if (dbParam == null) {
+                throw new ServiceException("宸ュ簭鍙傛暟涓嶅瓨鍦ㄦ垨涓嶅睘浜庡綋鍓嶅伐鍗曞伐搴忥紝ID=" + param.getId());
+            }
+            if (Objects.equals(dbParam.getInputValue(), param.getInputValue())) {
+                continue;
+            }
+            ProductionOrderRoutingOperationParam updateParam = new ProductionOrderRoutingOperationParam();
+            updateParam.setId(dbParam.getId());
+            updateParam.setInputValue(param.getInputValue());
+            productionOrderRoutingOperationParamMapper.updateById(updateParam);
+        }
+    }
+
+    private List<ProductStructureDto> resolveInputStructures(Long productionOrderId,
+                                                             ProductionOrderRoutingOperation routingOperation,
+                                                             Long outputProductModelId) {
+        if (productionOrderId == null || routingOperation == null || routingOperation.getTechnologyOperationId() == null) {
+            return new ArrayList<>();
+        }
+        ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
+                Wrappers.<ProductionOrderBom>lambdaQuery()
+                        .eq(ProductionOrderBom::getProductionOrderId, productionOrderId)
+                        .orderByDesc(ProductionOrderBom::getId)
+                        .last("limit 1"));
+        if (orderBom == null || orderBom.getId() == null) {
+            return new ArrayList<>();
+        }
+
+        List<ProductionBomStructure> bomNodeList = productionBomStructureMapper.selectList(
+                Wrappers.<ProductionBomStructure>lambdaQuery()
+                        .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
+                        .orderByAsc(ProductionBomStructure::getId));
+        if (bomNodeList.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        Map<Long, ProductionBomStructure> nodeMap = bomNodeList.stream()
+                .filter(item -> item != null && item.getId() != null)
+                .collect(Collectors.toMap(ProductionBomStructure::getId, item -> item, (left, right) -> left));
+        Long currentOutputModelId = routingOperation.getProductModelId() != null
+                ? routingOperation.getProductModelId()
+                : outputProductModelId;
+
+        Map<Long, BigDecimal> unitQtyByProductModel = new LinkedHashMap<>();
+        for (ProductionBomStructure node : bomNodeList) {
+            if (node == null || node.getParentId() == null || node.getProductModelId() == null) {
+                continue;
+            }
+            if (!Objects.equals(node.getTechnologyOperationId(), routingOperation.getTechnologyOperationId())) {
+                continue;
+            }
+            ProductionBomStructure parent = nodeMap.get(node.getParentId());
+            if (parent == null || !Objects.equals(parent.getProductModelId(), currentOutputModelId)) {
+                continue;
+            }
+            unitQtyByProductModel.merge(node.getProductModelId(), defaultDecimal(node.getUnitQuantity()), BigDecimal::add);
+        }
+
+        List<ProductStructureDto> result = new ArrayList<>();
+        for (Map.Entry<Long, BigDecimal> entry : unitQtyByProductModel.entrySet()) {
+            if (entry.getValue().compareTo(BigDecimal.ZERO) <= 0) {
+                continue;
+            }
+            ProductStructureDto item = new ProductStructureDto();
+            item.setProductModelId(entry.getKey());
+            item.setUnitQuantity(entry.getValue());
+            result.add(item);
+        }
+        return result;
+    }
+
     private Boolean removeProductMainByProductionTask(ProductionProductMain productionProductMain) {
         // 鍒犻櫎鎶ュ伐闇�瑕佸悓姝ュ洖婊氳川妫�銆佸簱瀛樸�佸伐鏃舵牳绠楀拰璁㈠崟/宸ュ崟杩涘害銆�
         List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
@@ -296,7 +397,7 @@
             productionOperationTaskMapper.updateById(productionOperationTask);
 
             ProductionOrder productionOrder = productionOrderMapper.selectById(productionOperationTask.getProductionOrderId());
-            ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOperationTask.getTechnologyRoutingOperationId());
+            ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOperationTask.getProductionOrderRoutingOperationId());
             if (productionOrder != null && routingOperation != null) {
                 // 鍙湁鏈�鍚庝竴閬撳伐搴忕殑鎶ュ伐鎵嶄細褰卞搷鐢熶骇璁㈠崟瀹屽伐鏁伴噺銆�
                 List<ProductionOrderRoutingOperation> routingOperationList = productionOrderRoutingOperationMapper.selectList(
@@ -363,6 +464,13 @@
         return value == null ? BigDecimal.ZERO : value;
     }
 
+    private Long resolveTaskId(ProductionProductMainDto dto) {
+        if (dto == null) {
+            return null;
+        }
+        return dto.getProductionOperationTaskId();
+    }
+
     @Override
     public ArrayList<Long> listMain(List<Long> idList) {
         return productionProductMainMapper.listMain(idList);

--
Gitblit v1.9.3