From 3066a8f5c1f475997bfe23857ba4bae9395900c4 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期四, 13 八月 2026 10:19:24 +0800
Subject: [PATCH] fix: 领料功能修改,移除订单领料,添加工序领料功能,支持按工序查询物料与已领料记录

---
 src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java |  179 +++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 100 insertions(+), 79 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 4fd9846..cec4b7e 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -16,16 +16,19 @@
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.bean.BeanUtils;
 import com.ruoyi.procurementrecord.utils.StockUtils;
-import com.ruoyi.production.bean.dto.ProductStructureDto;
 import com.ruoyi.production.bean.dto.ProductionProductMainDto;
 import com.ruoyi.production.enums.ProductOrderStatusEnum;
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.production.pojo.*;
+import com.ruoyi.production.service.ProductionOrderPickService;
 import com.ruoyi.production.service.ProductionProductMainService;
 import com.ruoyi.project.system.domain.SysUser;
 import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.quality.mapper.*;
 import com.ruoyi.quality.pojo.*;
+import com.ruoyi.stock.pojo.StockInRecord;
+import com.ruoyi.stock.pojo.StockInventory;
+import com.ruoyi.stock.service.StockInRecordService;
 import com.ruoyi.stock.dto.StockInventoryDto;
 import com.ruoyi.stock.service.StockInventoryService;
 import com.ruoyi.technology.mapper.TechnologyOperationMapper;
@@ -40,15 +43,7 @@
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 @Service
@@ -70,13 +65,14 @@
     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 ProductionOrderPickMapper productionOrderPickMapper;
+    private final ProductionOrderPickService productionOrderPickService;
     private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
     private final TechnologyOperationMapper technologyOperationMapper;
     private final StockUtils stockUtils;
+    private final StockInRecordService stockInRecordService;
     private final StockInventoryService stockInventoryService;
 
     @Override
@@ -259,6 +255,11 @@
         if (productionOrder == null) {
             throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
         }
+        // 鎶ュ伐鍓嶇疆鏉′欢锛氬綋鍓嶅伐搴忓繀椤诲凡缁忛鏂欙紙浠讳竴鐗╂枡鍑�棰嗘枡鏁伴噺澶т簬0锛夈��
+        // 璇ユ牎楠屽湪浜嬪姟鍐呮墽琛岋紝缁曡繃鍓嶇鐩存帴璋冪敤鎺ュ彛鍚屾牱鍙楅檺銆�
+        if (!productionOrderPickService.hasEffectivePick(taskId)) {
+            throw new ServiceException("褰撳墠宸ュ簭鏈鏂欙紝鏃犳硶鎶ュ伐");
+        }
         TechnologyRoutingOperation technologyRoutingOperation = technologyRoutingOperationMapper.selectById(routingOperation.getTechnologyRoutingOperationId());
         TechnologyOperation technologyOperation = technologyRoutingOperation == null ? null
                 : technologyOperationMapper.selectById(technologyRoutingOperation.getTechnologyOperationId());
@@ -278,24 +279,9 @@
         productionProductMainMapper.insert(productionProductMain);
         syncOperationParamInputValue(dto, routingOperation.getId(), productionProductMain.getId());
 
-        List<ProductStructureDto> productStructureDtos = resolveInputStructures(
-                productionOrder.getId(), routingOperation, productModel.getId());
-       // 濡傛灉娌℃湁bom瀛愯妭鐐逛簡锛岄偅涔堟姇鍏ュ氨鏄粬鏈韩
-        if (productStructureDtos.isEmpty()) {
-            ProductStructureDto fallbackInput = new ProductStructureDto();
-            fallbackInput.setProductModelId(productModel.getId());
-            fallbackInput.setUnitQuantity(BigDecimal.ONE);
-            productStructureDtos.add(fallbackInput);
-        }
-        for (ProductStructureDto item : productStructureDtos) {
-            // 褰撳墠瀹炵幇鎸夊伐搴忔垚鍝佺洿鎺ヤ綔涓烘姇鍏ワ紝鍚庣画鑻ユ帴鍏ラ鏂欒褰曞彲鍦ㄨ繖閲屾浛鎹㈡潵婧愩��
-            ProductionProductInput productionProductInput = new ProductionProductInput();
-            productionProductInput.setProductionProductMainId(productionProductMain.getId());
-            productionProductInput.setProductModelId(item.getProductModelId());
-            productionProductInput.setInputQuantity(item.getUnitQuantity().multiply(defaultDecimal(dto.getQuantity())));
-            productionProductInput.setQuantity(productionProductInput.getInputQuantity());
-            productionProductInputMapper.insert(productionProductInput);
-        }
+        // 鎶ュ伐鎶曞叆鏉ユ簮浜庡綋鍓嶅伐搴忕殑瀹為檯棰嗘枡璁板綍锛屼笉鍐嶆寜 BOM 鍗曚綅鐢ㄩ噺 脳 鎶ュ伐鏁伴噺鎺ㄧ畻銆�
+        // 姣忔潯鏈夋晥棰嗘枡鍙細琚娆℃姤宸ュ綊闆嗕竴娆★紝閲嶅鎶ュ伐涓嶄細閲嶅璁″叆鍚屼竴鎵圭墿鏂欍��
+        insertInputsFromTaskPicks(taskId, productionProductMain.getId());
 
         ProductionProductOutput productionProductOutput = new ProductionProductOutput();
         productionProductOutput.setProductionProductMainId(productionProductMain.getId());
@@ -304,7 +290,9 @@
         productionProductOutput.setScrapQty(defaultDecimal(dto.getScrapQty()));
         productionProductOutputMapper.insert(productionProductOutput);
         BigDecimal reportQty = defaultDecimal(productionProductOutput.getQuantity());
+        BigDecimal scrapQty = defaultDecimal(productionProductOutput.getScrapQty());
         BigDecimal productQty = reportQty;
+        String qualifiedBatchNo = null;
 
         List<ProductionOrderRoutingOperation> routingOperationList = productionOrderRoutingOperationMapper.selectList(
                 Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
@@ -350,6 +338,17 @@
                 stockInventoryDto.setQualitity(productQty);
                 stockInventoryDto.setProductModelId(productModel.getId());
                 stockInventoryService.addStockInRecordOnly(stockInventoryDto);
+                qualifiedBatchNo = resolveLatestStockInBatchNo(
+                        productionProductMain.getId(),
+                        StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(),
+                        productModel.getId(),
+                        "0");
+
+                //StockInRecord stockInRecord = stockInRecordService.getOne(Wrappers.<StockInRecord>lambdaQuery()
+                //        .eq(StockInRecord::getRecordId, productionProductMain.getId())
+                //        .eq(StockInRecord::getRecordType, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode())
+                //);
+                //stockInRecordService.batchApprove(Collections.singletonList(stockInRecord.getId()),1);
             }
 
             productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).add(productQty));
@@ -391,12 +390,42 @@
             productionAccount.setSchedulingUserId(user == null ? null : user.getUserId());
             productionAccount.setSchedulingUserName(user == null ? dto.getUserName() : user.getNickName());
             productionAccount.setFinishedNum(productQty);
-            productionAccount.setWorkHours(workHours);
+            productionAccount.setWorkHours(technologyOperation != null ? technologyOperation.getSalaryQuota() : null);
             productionAccount.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
             productionAccount.setSchedulingDate(LocalDateTime.now());
             productionAccountMapper.insert(productionAccount);
         }
+        if (scrapQty.compareTo(BigDecimal.ZERO) > 0) {
+            stockUtils.addUnStockWithBatchNo(
+                    productModel.getId(),
+                    scrapQty,
+                    StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(),
+                    productionProductMain.getId(),
+                    qualifiedBatchNo);
+        }
         return true;
+    }
+
+    private String resolveLatestStockInBatchNo(Long recordId,
+                                               String recordType,
+                                               Long productModelId,
+                                               String stockType) {
+        if (recordId == null || productModelId == null) {
+            return null;
+        }
+        StockInRecord stockInRecord = stockInRecordService.getOne(
+                Wrappers.<StockInRecord>lambdaQuery()
+                        .eq(StockInRecord::getRecordId, recordId)
+                        .eq(StockInRecord::getRecordType, recordType)
+                        .eq(StockInRecord::getProductModelId, productModelId)
+                        .eq(StockInRecord::getType, stockType)
+                        .orderByDesc(StockInRecord::getId)
+                        .last("limit 1"),
+                false);
+        if (stockInRecord == null) {
+            throw new ServiceException("鏈壘鍒板搴旂殑鍏ュ簱鐢宠璁板綍");
+        }
+        return stockInRecord.getBatchNo();
     }
 
     private void syncOperationParamInputValue(ProductionProductMainDto dto,
@@ -464,62 +493,54 @@
         return target;
     }
 
-    private List<ProductStructureDto> resolveInputStructures(Long productionOrderId,
-                                                             ProductionOrderRoutingOperation routingOperation,
-                                                             Long outputProductModelId) {
-        if (productionOrderId == null || routingOperation == null || routingOperation.getTechnologyOperationId() == null) {
-            return new ArrayList<>();
+    /**
+     * 鐢ㄥ綋鍓嶅伐搴忓皻鏈鎶ュ伐褰掗泦鐨勫疄闄呴鏂欑敓鎴愭姤宸ユ姇鍏ャ��
+     * 鎶曞叆鏁伴噺鍙栧噣棰嗘枡鏁伴噺锛堥鏂�+琛ユ枡-閫�鏂欙級锛屽苟璁板綍鏉ユ簮棰嗘枡ID锛�
+     * 淇濊瘉鍚屼竴绗旈鏂欎笉浼氬湪澶氭鎶ュ伐涓閲嶅璁″叆銆�
+     */
+    private void insertInputsFromTaskPicks(Long productionOperationTaskId, Long productionProductMainId) {
+        if (productionOperationTaskId == null || productionProductMainId == null) {
+            return;
         }
-        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<ProductionOrderPick> taskPickList = productionOrderPickMapper.selectList(
+                Wrappers.<ProductionOrderPick>lambdaQuery()
+                        .eq(ProductionOrderPick::getProductionOperationTaskId, productionOperationTaskId)
+                        .orderByAsc(ProductionOrderPick::getId));
+        if (taskPickList.isEmpty()) {
+            return;
         }
+        List<Long> pickIdList = taskPickList.stream()
+                .map(ProductionOrderPick::getId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+        Set<Long> consumedPickIdSet = pickIdList.isEmpty()
+                ? Collections.emptySet()
+                : productionProductInputMapper.selectList(
+                        Wrappers.<ProductionProductInput>lambdaQuery()
+                                .in(ProductionProductInput::getProductionOrderPickId, pickIdList))
+                .stream()
+                .map(ProductionProductInput::getProductionOrderPickId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
 
-        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) {
+        for (ProductionOrderPick pick : taskPickList) {
+            if (pick == null || pick.getId() == null || consumedPickIdSet.contains(pick.getId())) {
                 continue;
             }
-            if (!Objects.equals(node.getTechnologyOperationId(), routingOperation.getTechnologyOperationId())) {
+            BigDecimal effectiveQuantity = defaultDecimal(pick.getQuantity())
+                    .add(defaultDecimal(pick.getFeedingQty()))
+                    .subtract(defaultDecimal(pick.getReturnQty()));
+            if (effectiveQuantity.compareTo(BigDecimal.ZERO) <= 0) {
                 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);
+            ProductionProductInput productionProductInput = new ProductionProductInput();
+            productionProductInput.setProductionProductMainId(productionProductMainId);
+            productionProductInput.setProductModelId(pick.getProductModelId());
+            productionProductInput.setProductionOrderPickId(pick.getId());
+            productionProductInput.setInputQuantity(effectiveQuantity);
+            productionProductInput.setQuantity(effectiveQuantity);
+            productionProductInputMapper.insert(productionProductInput);
         }
-
-        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) {

--
Gitblit v1.9.3