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/ProductionOrderServiceImpl.java |  184 +++++++++++++++++++++++++++++++--------------
 1 files changed, 127 insertions(+), 57 deletions(-)

diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
index 6ef6a44..e9a0487 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -22,6 +22,8 @@
 import com.ruoyi.production.bean.vo.ProductionOrderVo;
 import com.ruoyi.production.bean.vo.ProductionPlanVo;
 import com.ruoyi.production.bean.vo.ProductionOrderWorkOrderDetailVo;
+import com.ruoyi.production.bean.vo.ProcessRouteStatusVo;
+import com.ruoyi.production.bean.vo.ProductionOrderProcessTaskVo;
 import com.ruoyi.production.enums.ProductOrderStatusEnum;
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.production.pojo.*;
@@ -32,6 +34,7 @@
 import com.ruoyi.quality.pojo.QualityInspectFile;
 import com.ruoyi.quality.pojo.QualityInspectParam;
 import com.ruoyi.production.service.ProductionOrderService;
+import com.ruoyi.production.util.TaskPlanQuantityUtil;
 import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.stock.mapper.StockInventoryMapper;
@@ -59,6 +62,7 @@
     private final ProductionOperationTaskMapper productionOperationTaskMapper;
     private final ProductionOrderBomMapper productionOrderBomMapper;
     private final ProductionBomStructureMapper productionBomStructureMapper;
+    private final ProductionOrderMapper productionOrderMapper;
     private final ProductionProductMainMapper productionProductMainMapper;
     private final ProductionProductOutputMapper productionProductOutputMapper;
     private final ProductionOrderPickMapper productionOrderPickMapper;
@@ -85,6 +89,7 @@
         // 鍒嗛〉鏌ヨ鐢熶骇璁㈠崟
         Page<ProductionOrderVo> result = (Page<ProductionOrderVo>) baseMapper.pageProductionOrder(page, dto);
         fillProductImages(result.getRecords());
+        fillProcessRouteStatus(result.getRecords());
         return result;
     }
 
@@ -93,6 +98,7 @@
         // 鏌ヨ鐢熶骇璁㈠崟鍒楄〃
         List<ProductionOrderVo> records = baseMapper.listProductionOrder(dto);
         fillProductImages(records);
+        fillProcessRouteStatus(records);
         return records;
     }
 
@@ -132,7 +138,7 @@
                 || !Objects.equals(oldOrder.getProductModelId(), productionOrder.getProductModelId())
                 || compareDecimal(oldOrder.getQuantity(), productionOrder.getQuantity()) != 0
                 || productionOrderRoutingMapper.selectCount(Wrappers.<ProductionOrderRouting>lambdaQuery()
-                        .eq(ProductionOrderRouting::getProductionOrderId, productionOrder.getId())) == 0);
+                .eq(ProductionOrderRouting::getProductionOrderId, productionOrder.getId())) == 0);
         if (needSync) {
             syncProductionOrderSnapshot(productionOrder.getId());
         }
@@ -188,7 +194,6 @@
             ProductionOrder update = new ProductionOrder();
             update.setId(productionOrder.getId());
             update.setTechnologyRoutingId(targetRoutingId);
-        // 鎸佷箙鍖栨垨杈撳嚭澶勭悊缁撴灉
             if (!this.updateById(update)) {
                 throw new ServiceException("缁戝畾宸ヨ壓璺嚎澶辫触");
             }
@@ -228,6 +233,7 @@
         clearProductionSnapshot(productionOrderId);
         ProductionOrderBom orderBom = syncProductionOrderBomSnapshot(productionOrder, technologyRouting);
 
+        //鐢熶骇璁㈠崟宸ヨ壓璺嚎琛�
         ProductionOrderRouting orderRouting = new ProductionOrderRouting();
         orderRouting.setProductionOrderId(productionOrder.getId());
         orderRouting.setTechnologyRoutingId(technologyRouting.getId());
@@ -236,7 +242,6 @@
         orderRouting.setDescription(technologyRouting.getDescription());
         orderRouting.setBomId(technologyRouting.getBomId());
         orderRouting.setOrderBomId(orderBom == null ? null : orderBom.getId());
-        // 鎸佷箙鍖栨垨杈撳嚭澶勭悊缁撴灉
         productionOrderRoutingMapper.insert(orderRouting);
 
         int syncedParamCount = 0;
@@ -246,8 +251,10 @@
                         .eq(TechnologyRoutingOperation::getTechnologyRoutingId, technologyRouting.getId())
                         .orderByDesc(TechnologyRoutingOperation::getDragSort)
                         .orderByDesc(TechnologyRoutingOperation::getId));
+        // 鎵佸钩 BOM 涓嶉厤缃暟閲忥紝宸ュ崟璁″垝鏁伴噺缁熶竴鍙栬鍗曟暟閲忋��
+        BigDecimal taskPlanQuantity = TaskPlanQuantityUtil.resolveTaskPlanQuantity(productionOrder);
         Map<Long, String> operationNameMap = technologyOperationMapper.selectBatchIds(
-        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
+                        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
                         routingOperations.stream()
                                 .map(TechnologyRoutingOperation::getTechnologyOperationId)
                                 .filter(Objects::nonNull)
@@ -271,6 +278,7 @@
             targetOperation.setIsQuality(sourceOperation.getIsQuality());
             targetOperation.setOperationName(operationNameMap.get(sourceOperation.getTechnologyOperationId()));
             targetOperation.setTechnologyOperationId(sourceOperation.getTechnologyOperationId());
+            targetOperation.setType(sourceOperation.getType());
             productionOrderRoutingOperationMapper.insert(targetOperation);
 
             boolean isLastOperation = lastDragSort != null && Objects.equals(sourceOperation.getDragSort(), lastDragSort);
@@ -278,7 +286,7 @@
                 ProductionOperationTask task = new ProductionOperationTask();
                 task.setProductionOrderRoutingOperationId(targetOperation.getId());
                 task.setProductionOrderId(productionOrder.getId());
-                task.setPlanQuantity(defaultDecimal(productionOrder.getQuantity()));
+                task.setPlanQuantity(taskPlanQuantity);
                 task.setCompleteQuantity(BigDecimal.ZERO);
                 task.setWorkOrderNo(generateNextTaskNo());
                 task.setStatus(2);
@@ -313,8 +321,11 @@
         return syncedParamCount;
     }
 
+    /**
+     * 鍚屾璁㈠崟BOM蹇収锛氭墎骞冲鍒垛�滅墿鏂欒鏍� + 娑堣�楀伐搴忊�濆叧绯汇��
+     * 涓嶅啀鐢熸垚鎴愬搧鏍硅妭鐐癸紝涔熶笉鍐嶈绠楀崟浣嶇敤閲忓拰闇�姹傛暟閲忋��
+     */
     private ProductionOrderBom syncProductionOrderBomSnapshot(ProductionOrder productionOrder, TechnologyRouting technologyRouting) {
-        // 鍚屾璁㈠崟BOM蹇収缁撴瀯
         if (technologyRouting.getBomId() == null) {
             return null;
         }
@@ -322,39 +333,32 @@
         if (technologyBom == null) {
             throw new ServiceException("宸ヨ壓BOM涓嶅瓨鍦�");
         }
-        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
+        // 鍙彇鐪熷疄鐗╂枡琛岋細蹇呴』鏈夋秷鑰楀伐搴忥紝鍘嗗彶鎴愬搧鏍硅妭鐐癸紙鏃犲伐搴忥級涓嶅睘浜庣墿鏂�
         List<TechnologyBomStructure> structureList = technologyBomStructureMapper.selectList(
                 Wrappers.<TechnologyBomStructure>lambdaQuery()
                         .eq(TechnologyBomStructure::getBomId, technologyBom.getId())
+                        .isNotNull(TechnologyBomStructure::getOperationId)
                         .orderByAsc(TechnologyBomStructure::getId));
-        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
-        TechnologyBomStructure root = structureList.stream().filter(item -> item.getParentId() == null).findFirst().orElse(null);
-        BigDecimal orderQuantity = defaultDecimal(productionOrder.getQuantity());
 
         ProductionOrderBom orderBom = new ProductionOrderBom();
         orderBom.setProductionOrderId(productionOrder.getId());
         orderBom.setBomId(Long.valueOf(technologyBom.getId()));
-        orderBom.setProductModelId(root != null ? root.getProductModelId() : productionOrder.getProductModelId());
+        // BOM 涓昏〃鏈韩鍗充唬琛ㄦ垚鍝佽鏍�
+        orderBom.setProductModelId(technologyBom.getProductModelId() != null
+                ? technologyBom.getProductModelId()
+                : productionOrder.getProductModelId());
         orderBom.setRemark(technologyBom.getRemark());
         orderBom.setBomNo(technologyBom.getBomNo());
         orderBom.setVersion(technologyBom.getVersion());
-        // 鎸佷箙鍖栨垨杈撳嚭澶勭悊缁撴灉
         productionOrderBomMapper.insert(orderBom);
 
-        Map<Long, Long> idMap = new HashMap<>();
         for (TechnologyBomStructure source : structureList) {
-            // 瀛愯妭鐐� parentId 闇�瑕佹槧灏勬垚鏂板揩鐓ц妭鐐� id锛屾墠鑳戒繚鐣欏師濮� BOM 灞傜骇銆�
             ProductionBomStructure target = new ProductionBomStructure();
             target.setProductionOrderId(productionOrder.getId());
             target.setProductionOrderBomId(orderBom.getId());
-            target.setParentId(source.getParentId() == null ? null : idMap.get(source.getParentId()));
             target.setProductModelId(source.getProductModelId());
             target.setTechnologyOperationId(source.getOperationId());
-            target.setUnitQuantity(source.getUnitQuantity());
-            target.setDemandedQuantity(source.getUnitQuantity().multiply(orderQuantity));
-            target.setUnit(source.getUnit());
             productionBomStructureMapper.insert(target);
-            idMap.put(source.getId(), target.getId());
         }
         return orderBom;
     }
@@ -362,7 +366,7 @@
     private void clearProductionSnapshot(Long productionOrderId) {
         // 娓呯悊璁㈠崟宸茬敓鎴愮殑宸ヨ壓涓嶣OM蹇収鏁版嵁
         boolean hasPickRecord = productionOrderPickRecordMapper.selectCount(
-        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
+                // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
                 Wrappers.<ProductionOrderPickRecord>lambdaQuery()
                         .eq(ProductionOrderPickRecord::getProductionOrderId, productionOrderId)) > 0;
         // 鍙傛暟涓庡墠缃潯浠舵牎楠�
@@ -372,7 +376,7 @@
         List<Long> taskIds = productionOperationTaskMapper.selectList(
                         Wrappers.<ProductionOperationTask>lambdaQuery()
                                 .eq(ProductionOperationTask::getProductionOrderId, productionOrderId))
-        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
+                // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
                 .stream().map(ProductionOperationTask::getId).collect(Collectors.toList());
         if (!taskIds.isEmpty()) {
             // 宸叉湁鎶ュ伐璁板綍璇存槑璁㈠崟宸插紑宸ワ紝姝ゆ椂涓嶅厑璁稿啀閲嶅缓蹇収銆�
@@ -714,6 +718,46 @@
         }
     }
 
+    private void fillProcessRouteStatus(List<ProductionOrderVo> records) {
+        if (records == null || records.isEmpty()) {
+            return;
+        }
+        List<Long> orderIds = records.stream()
+                .map(ProductionOrderVo::getId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        if (orderIds.isEmpty()) {
+            return;
+        }
+
+        List<ProductionOrderProcessTaskVo> tasks = productionOperationTaskMapper.listProcessStatusByOrderIds(orderIds);
+        Map<Long, List<ProcessRouteStatusVo>> statusMap = new LinkedHashMap<>();
+        if (tasks != null) {
+            for (ProductionOrderProcessTaskVo task : tasks) {
+                if (task == null || task.getProductionOrderId() == null) {
+                    continue;
+                }
+                ProcessRouteStatusVo status = new ProcessRouteStatusVo();
+                status.setName(task.getOperationName() != null && !task.getOperationName().isBlank()
+                        ? task.getOperationName()
+                        : "鏈煡宸ュ簭");
+                BigDecimal percentage = task.getCompletionStatus() == null
+                        ? BigDecimal.ZERO
+                        : task.getCompletionStatus();
+                if (percentage.compareTo(new BigDecimal("100")) > 0) {
+                    percentage = new BigDecimal("100");
+                }
+                status.setPercentage(percentage);
+                statusMap.computeIfAbsent(task.getProductionOrderId(), key -> new ArrayList<>()).add(status);
+            }
+        }
+
+        for (ProductionOrderVo record : records) {
+            record.setProcessRouteStatus(statusMap.getOrDefault(record.getId(), Collections.emptyList()));
+        }
+    }
+
     private StorageBlobVO toStorageBlobVO(StorageBlob blob) {
         // 灏嗗瓨鍌ㄦ枃浠跺璞¤浆鎹负VO
         StorageBlobVO vo = BeanUtil.copyProperties(blob, StorageBlobVO.class);
@@ -741,12 +785,12 @@
                 new Page<ProductionOperationTaskVo>(1, -1), taskQuery);
         List<ProductionOperationTaskVo> workOrderList = workOrderPage == null || workOrderPage.getRecords() == null
                 ? Collections.emptyList()
-        // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
+                // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
                 : workOrderPage.getRecords().stream()
                 .filter(Objects::nonNull)
                 .sorted(Comparator.comparing(ProductionOperationTaskVo::getId, Comparator.nullsLast(Comparator.naturalOrder())))
-                .collect(Collectors.toList());
-        if (workOrderList == null || workOrderList.isEmpty()) {
+                .toList();
+        if (workOrderList.isEmpty()) {
             detailVo.setWorkOrderList(Collections.emptyList());
             return detailVo;
         }
@@ -757,7 +801,7 @@
                 .collect(Collectors.toList());
         List<ProductionProductMain> reportMainList = workOrderIdList.isEmpty()
                 ? Collections.emptyList()
-        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
+                // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
                 : productionProductMainMapper.selectList(
                 Wrappers.<ProductionProductMain>lambdaQuery()
                         .in(ProductionProductMain::getProductionOperationTaskId, workOrderIdList)
@@ -788,12 +832,10 @@
                 if (reportOutput == null) {
                     continue;
                 }
-                Long reportMainId = reportOutput.getProductionProductMainId() != null
-                        ? reportOutput.getProductionProductMainId()
-                        : reportOutput.getProductMainId();
-                if (reportMainId == null) {
+                if (reportOutput.getProductionProductMainId() == null) {
                     continue;
                 }
+                Long reportMainId = reportOutput.getProductionProductMainId();
                 reportOutputMap.computeIfAbsent(reportMainId, k -> new ArrayList<>()).add(reportOutput);
             }
 
@@ -868,6 +910,7 @@
 
                 ProductionOrderWorkOrderDetailVo.ReportDetail reportDetail = new ProductionOrderWorkOrderDetailVo.ReportDetail();
                 reportDetail.setReportMain(reportMain);
+                reportDetail.setWorkHour(reportMain.getWorkHour());
                 reportDetail.setReportOutputList(reportOutputMap.getOrDefault(reportMainId, Collections.emptyList()));
                 reportDetail.setReportParamList(reportParamMap.getOrDefault(reportMainId, Collections.emptyList()));
                 reportDetailList.add(reportDetail);
@@ -878,6 +921,7 @@
                     inspectDetail.setReportId(reportMainId);
                     inspectDetail.setReportNo(reportMain.getProductNo());
                     inspectDetail.setReportMain(reportMain);
+                    inspectDetail.setWorkHour(reportMain.getWorkHour());
                     inspectDetail.setInspect(inspect);
                     inspectDetail.setInspectParamList(inspectParamMap.getOrDefault(inspect.getId(), Collections.emptyList()));
                     inspectDetail.setInspectFileList(inspectFileMap.getOrDefault(inspect.getId(), Collections.emptyList()));
@@ -917,12 +961,20 @@
 
     @Override
     public List<ProductionOrderPickVo> pick(Long productionOrderId) {
-        // 鏌ヨ璁㈠崟棰嗘枡銆佹姇鏂欎笌閫�鏂欐槑缁�
+        return pick(productionOrderId, null);
+    }
+
+    /**
+     * 鎸夎鍗旴OM蹇収缁欏嚭鍙鐢ㄧ墿鏂欏缓璁��
+     * 鎵佸钩BOM鍙弿杩扳�滅墿鏂欒鏍� + 娑堣�楀伐搴忊�濓紝鍥犳杩欓噷涓嶅啀璁$畻闇�姹傛暟閲忥紱
+     * 浼犲叆宸ュ簭ID鏃跺彧杩斿洖璇ュ伐搴忕殑鐗╂枡銆�
+     */
+    @Override
+    public List<ProductionOrderPickVo> pick(Long productionOrderId, Long technologyOperationId) {
         if (productionOrderId == null) {
             return Collections.emptyList();
         }
 
-        // 鏌ヨ骞跺噯澶囦笟鍔℃暟鎹�
         ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
                 Wrappers.<ProductionOrderBom>lambdaQuery()
                         .eq(ProductionOrderBom::getProductionOrderId, productionOrderId)
@@ -932,13 +984,35 @@
             return Collections.emptyList();
         }
 
-        List<ProductionBomStructureVo> bomStructureList = productionBomStructureMapper.pickByBomId(orderBom.getId());
+        List<ProductionBomStructureVo> bomStructureList = productionBomStructureMapper.listByBomId(orderBom.getId());
         if (bomStructureList == null || bomStructureList.isEmpty()) {
             return Collections.emptyList();
         }
 
+        ProductionOrder productionOrder = productionOrderMapper.selectById(productionOrderId);
+
+        // 鎴愬搧瑙勬牸涓嶉渶瑕侀鏂欙細鍏煎鍘嗗彶蹇収涓彲鑳藉瓨鍦ㄧ殑鎴愬搧鏍硅妭鐐�
+        Set<Long> finishedProductModelIds = new HashSet<>();
+        if (productionOrder != null && productionOrder.getProductModelId() != null) {
+            finishedProductModelIds.add(productionOrder.getProductModelId());
+        }
+        if (orderBom.getProductModelId() != null) {
+            finishedProductModelIds.add(orderBom.getProductModelId());
+        }
+
+        List<ProductionBomStructureVo> materialStructureList = bomStructureList.stream()
+                .filter(Objects::nonNull)
+                .filter(s -> s.getProductModelId() != null && !finishedProductModelIds.contains(s.getProductModelId()))
+                .filter(s -> s.getTechnologyOperationId() != null)
+                .filter(s -> technologyOperationId == null
+                        || technologyOperationId.equals(s.getTechnologyOperationId()))
+                .collect(Collectors.toList());
+        if (materialStructureList.isEmpty()) {
+            return Collections.emptyList();
+        }
+
         // 閬嶅巻澶勭悊鏁版嵁骞剁粍瑁呯粨鏋�
-        List<Long> productModelIds = bomStructureList.stream()
+        List<Long> productModelIds = materialStructureList.stream()
                 .map(ProductionBomStructureVo::getProductModelId)
                 .filter(Objects::nonNull)
                 .distinct()
@@ -948,7 +1022,8 @@
         if (!productModelIds.isEmpty()) {
             List<StockInventory> stockList = stockInventoryMapper.selectList(
                     Wrappers.<StockInventory>lambdaQuery()
-                            .in(StockInventory::getProductModelId, productModelIds));
+                            .in(StockInventory::getProductModelId, productModelIds)
+                            .gt(StockInventory::getQualitity, BigDecimal.ZERO));
             for (StockInventory stockItem : stockList) {
                 if (stockItem == null || stockItem.getProductModelId() == null) {
                     continue;
@@ -963,31 +1038,26 @@
         }
 
         Map<String, ProductionOrderPickVo> mergedPickMap = new LinkedHashMap<>();
-        for (ProductionBomStructureVo structure : bomStructureList) {
-            if (structure == null || structure.getProductModelId() == null) {
+        for (ProductionBomStructureVo structure : materialStructureList) {
+            Long productModelId = structure.getProductModelId();
+            String mergeKey = structure.getTechnologyOperationId() + "#" + productModelId;
+            if (mergedPickMap.containsKey(mergeKey)) {
                 continue;
             }
-            Long productModelId = structure.getProductModelId();
-            String mergeKey = String.valueOf(structure.getTechnologyOperationId()) + "#" + productModelId;
-            ProductionOrderPickVo vo = mergedPickMap.get(mergeKey);
-            if (vo == null) {
-                vo = new ProductionOrderPickVo();
-                vo.setProductModelId(productModelId);
-                vo.setOperationName(structure.getOperationName());
-                vo.setTechnologyOperationId(structure.getTechnologyOperationId());
-                vo.setProductName(structure.getProductName());
-                vo.setModel(structure.getModel());
-                vo.setDemandedQuantity(BigDecimal.ZERO);
-                vo.setUnit(structure.getUnit());
-                List<String> batchNoList = stockBatchNoMap.get(productModelId) == null
-                        ? Collections.emptyList()
-                        : new ArrayList<>(stockBatchNoMap.get(productModelId));
-                vo.setBatchNoList(batchNoList);
-                vo.setStockQuantity(stockQuantityMap.getOrDefault(productModelId, BigDecimal.ZERO));
-                vo.setBom(true);
-                mergedPickMap.put(mergeKey, vo);
-            }
-            vo.setDemandedQuantity(defaultDecimal(vo.getDemandedQuantity()).add(defaultDecimal(structure.getDemandedQuantity())));
+            ProductionOrderPickVo vo = new ProductionOrderPickVo();
+            vo.setProductModelId(productModelId);
+            vo.setOperationName(structure.getOperationName());
+            vo.setTechnologyOperationId(structure.getTechnologyOperationId());
+            vo.setProductName(structure.getProductName());
+            vo.setModel(structure.getModel());
+            vo.setUnit(structure.getUnit());
+            List<String> batchNoList = stockBatchNoMap.get(productModelId) == null
+                    ? Collections.emptyList()
+                    : new ArrayList<>(stockBatchNoMap.get(productModelId));
+            vo.setBatchNoList(batchNoList);
+            vo.setStockQuantity(stockQuantityMap.getOrDefault(productModelId, BigDecimal.ZERO));
+            vo.setBom(true);
+            mergedPickMap.put(mergeKey, vo);
         }
         return new ArrayList<>(mergedPickMap.values());
     }

--
Gitblit v1.9.3