From 6ad5c2cdc193cf7bb02884961b7434cd7f607a0d Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 16 四月 2026 10:48:09 +0800
Subject: [PATCH] feat(production): 扩展生产工艺路线支持多产品绑定及工单权限控制

---
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java |  216 +++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 140 insertions(+), 76 deletions(-)

diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
index 6c681b8..82fcdba 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -5,14 +5,19 @@
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.basic.mapper.ProductMapper;
+import com.ruoyi.basic.mapper.ProductModelMapper;
+import com.ruoyi.basic.pojo.Product;
+import com.ruoyi.basic.pojo.ProductModel;
+import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
+import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.production.dto.ProductStructureDto;
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.production.pojo.*;
+import com.ruoyi.production.service.impl.ProductOrderServiceImpl;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.quality.mapper.QualityInspectMapper;
@@ -23,11 +28,12 @@
 import com.ruoyi.sales.mapper.SalesLedgerMapper;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
 import com.ruoyi.sales.mapper.ShippingInfoMapper;
-import com.ruoyi.sales.pojo.InvoiceRegistrationProduct;
 import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.pojo.ShippingInfo;
 import com.ruoyi.sales.service.ISalesLedgerProductService;
+import com.ruoyi.stock.mapper.StockInventoryMapper;
+import com.ruoyi.stock.pojo.StockInventory;
 import lombok.AllArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -38,6 +44,7 @@
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.function.Function;
@@ -60,6 +67,10 @@
 
     private PurchaseLedgerMapper purchaseLedgerMapper;
 
+    private ProductMapper productMapper;
+
+    private ProductModelMapper productModelMapper;
+
     private ProductOrderMapper productOrderMapper;
 
     private ProcessRouteItemMapper processRouteItemMapper;
@@ -77,6 +88,7 @@
     private ProductionProductInputMapper productionProductInputMapper;
     private QualityInspectMapper qualityInspectMapper;
     private ShippingInfoMapper shippingInfoMapper;
+    private ShippingInfoServiceImpl shippingInfoService;
 
     private StockUtils stockUtils;
 
@@ -84,6 +96,10 @@
 
     @Autowired
     private ProductStructureMapper productStructureMapper;
+    @Autowired
+    private StockInventoryMapper stockInventoryMapper;
+    @Autowired
+    private ProductOrderServiceImpl productOrderServiceImpl;
 
     @Override
     public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
@@ -107,6 +123,8 @@
                     item.setShippingDate(shippingInfo.getShippingDate());
                     item.setShippingCarNumber(shippingInfo.getShippingCarNumber());
                     item.setShippingStatus(shippingInfo.getStatus());
+                    item.setExpressCompany(shippingInfo.getExpressCompany());
+                    item.setExpressNumber(shippingInfo.getExpressNumber());
                 }
             });
             // 寮�绁�
@@ -152,6 +170,12 @@
         List<SalesLedgerProduct> deletedProducts = salesLedgerProductMapper.selectBatchIds(Arrays.asList(ids));
         if (deletedProducts.isEmpty()) {
             return 0; // 娌℃湁鍙垹闄ょ殑鏁版嵁
+        }
+        //鍒犻櫎鍙戣揣淇℃伅
+        List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
+                .in(ShippingInfo::getSalesLedgerProductId, Arrays.asList(ids)));
+        if(!CollectionUtils.isEmpty(shippingInfos)){
+            shippingInfoService.delete(shippingInfos.stream().map(ShippingInfo::getId).collect(Collectors.toList()));
         }
 
         // 鍙兘灞炰簬澶氫釜涓昏〃
@@ -202,6 +226,7 @@
         int result;
         Long salesLedgerId = salesLedgerProduct.getSalesLedgerId();
         if (salesLedgerProduct.getId() == null) {
+            salesLedgerProduct.setRegisterDate(LocalDateTime.now());
             result = salesLedgerProductMapper.insert(salesLedgerProduct);
             addProductionData(salesLedgerProduct);
         } else {
@@ -211,9 +236,7 @@
             /*鍒犻櫎瀵瑰簲鐨勭敓浜ф暟鎹苟閲嶆柊鏂板*/
             deleteProductionData(Arrays.asList(salesLedgerProduct.getId()));
             // 鍒犻櫎鐢熶骇鏍哥畻鏁版嵁
-            LambdaQueryWrapper<SalesLedgerProductionAccounting> reportWrapper = new LambdaQueryWrapper<>();
-            reportWrapper.in(SalesLedgerProductionAccounting::getSalesLedgerId, salesLedgerId);
-            salesLedgerProductionAccountingMapper.delete(reportWrapper);
+
             addProductionData(salesLedgerProduct);
         }
 
@@ -248,78 +271,103 @@
     }
 
     /**
+     * 閫氳繃浜у搧澶х被锛岃鏍煎瀷鍙锋煡璇roductModelId
+     */
+    public Long getProductModelId(String productCategory, String productSpecification) {
+        Product product = productMapper.selectOne(new QueryWrapper<Product>()
+                .lambda()
+                .eq(Product::getProductName, productCategory)
+                .orderByDesc(Product::getId)
+                .last("LIMIT 1"));
+        if(product == null){
+            throw new RuntimeException("璇峰厛娣诲姞浜у搧");
+        }
+        ProductModel productModel = productModelMapper.selectOne(new QueryWrapper<ProductModel>()
+                .lambda()
+                .eq(ProductModel::getProductId, product.getId())
+                .eq(ProductModel::getModel, productSpecification)
+                .orderByDesc(ProductModel::getId)
+                .last("LIMIT 1"));
+        return productModel == null ? null : productModel.getId();
+    }
+
+    /**
      * 鏂板鐢熶骇鏁版嵁
      */
     public void addProductionData(SalesLedgerProduct salesLedgerProduct) {
         ProductOrder productOrder = new ProductOrder();
         productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
-        productOrder.setProductModelId(salesLedgerProduct.getId());
-        productOrder.setNpsNo("SC" + String.format("%08d", salesLedgerProduct.getId()));
+        if(salesLedgerProduct.getProductModelId() == null){
+            Long productModelId = getProductModelId(salesLedgerProduct.getProductCategory(), salesLedgerProduct.getSpecificationModel());
+            productOrder.setProductModelId(productModelId);
+        }else{
+            productOrder.setProductModelId(salesLedgerProduct.getProductModelId());
+        }
+        productOrder.setSaleLedgerProductId(salesLedgerProduct.getId());
+        String string = productOrderServiceImpl.generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
+        productOrder.setNpsNo(string);
         productOrder.setQuantity(salesLedgerProduct.getQuantity());//闇�姹傛暟閲�
         productOrder.setCompleteQuantity(BigDecimal.ZERO);//瀹屾垚鏁伴噺
         productOrderMapper.insert(productOrder);
-
-        List<ProcessRoute> processRoutes = processRouteMapper.selectList(new QueryWrapper<ProcessRoute>().lambda()
-                .eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId())
-                .orderByDesc(ProcessRoute::getCreateTime));
-        if (processRoutes.size()>0){
-            ProcessRoute processRoute = processRoutes.get(0);
-            //鏂板鐢熶骇璁㈠崟宸ヨ壓璺嚎涓昏〃
-            ProductProcessRoute productProcessRoute = new ProductProcessRoute();
-            productProcessRoute.setProductModelId(processRoute.getProductModelId());
-            productProcessRoute.setProcessRouteCode(processRoute.getProcessRouteCode());
-            productProcessRoute.setProductOrderId(productOrder.getId());
-            productProcessRoute.setBomId(processRoute.getBomId());
-            productProcessRouteMapper.insert(productProcessRoute);
-            //鏂板鐢熶骇璁㈠崟宸ヨ壓璺嚎瀛愯〃
-            List<ProcessRouteItem> processRouteItems = processRouteItemMapper.selectList(new QueryWrapper<ProcessRouteItem>().lambda().eq(ProcessRouteItem::getRouteId, processRoute.getId()));
-            // 鐢熸垚褰撳墠鏃ユ湡鐨勫墠缂�锛氬勾鏈堟棩
-            String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
-            for (ProcessRouteItem processRouteItem : processRouteItems) {
-                ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
-                productProcessRouteItem.setProductModelId(processRouteItem.getProductModelId());
-                productProcessRouteItem.setProcessId(processRouteItem.getProcessId());
-                productProcessRouteItem.setProductOrderId(productOrder.getId());
-                productProcessRouteItem.setProductRouteId(productProcessRoute.getId());
-                productProcessRouteItem.setDragSort(processRouteItem.getDragSort());
-                int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
-                if (insert > 0) {
-                    // 鏌ヨ浠婃棩宸插瓨鍦ㄧ殑鏈�澶у伐鍗曞彿
-                    QueryWrapper<ProductWorkOrder> queryWrapper = new QueryWrapper<>();
-                    queryWrapper.likeRight("work_order_no", datePrefix)
-                            .orderByDesc("work_order_no")
-                            .last("LIMIT 1");
-
-                    ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectOne(queryWrapper);
-
-                    int sequenceNumber = 1; // 榛樿搴忓彿
-                    if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
-                        String lastNo = lastWorkOrder.getWorkOrderNo().toString();
-                        if (lastNo.startsWith(datePrefix)) {
-                            String seqStr = lastNo.substring(datePrefix.length());
-                            try {
-                                sequenceNumber = Integer.parseInt(seqStr) + 1;
-                            } catch (NumberFormatException e) {
-                                sequenceNumber = 1;
-                            }
-                        }
-                    }
-                    // 鐢熸垚瀹屾暣鐨勫伐鍗曞彿
-                    String workOrderNoStr = String.format("%s%03d", datePrefix, sequenceNumber);
-                    ProductWorkOrder productWorkOrder = new ProductWorkOrder();
-                    productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
-                    productWorkOrder.setProductOrderId(productOrder.getId());
-                    productWorkOrder.setPlanQuantity(salesLedgerProduct.getQuantity());
-                    productWorkOrder.setWorkOrderNo(workOrderNoStr);
-                    productWorkOrder.setStatus(1);
-
-                    productWorkOrderMapper.insert(productWorkOrder);
-                }
-
-            }
-            productOrder.setRouteId(processRoute.getId());
-            productOrderMapper.updateById(productOrder);
-        }
+        // 鍙栨秷榛樿鐨勫伐鑹鸿矾绾�
+//        List<ProcessRoute> processRoutes = processRouteMapper.selectList(
+//                new QueryWrapper<ProcessRoute>()
+//                        .and(wrapper -> wrapper.eq("product_model_id", salesLedgerProduct.getProductModelId())
+//                                .or()
+//                                .apply("find_in_set({0}, product_model_ids)", salesLedgerProduct.getProductModelId()))
+//                        .orderByDesc("create_time"));
+//        if (processRoutes.size()>0){
+//            ProcessRoute processRoute = processRoutes.get(0);
+//            //鏂板鐢熶骇璁㈠崟宸ヨ壓璺嚎涓昏〃
+//            ProductProcessRoute productProcessRoute = new ProductProcessRoute();
+//            productProcessRoute.setProductModelId(salesLedgerProduct.getProductModelId());
+//            productProcessRoute.setProcessRouteCode(processRoute.getProcessRouteCode());
+//            productProcessRoute.setProductOrderId(productOrder.getId());
+//            productProcessRoute.setBomId(processRoute.getBomId());
+//            productProcessRouteMapper.insert(productProcessRoute);
+//            //鏂板鐢熶骇璁㈠崟宸ヨ壓璺嚎瀛愯〃
+//            List<ProcessRouteItem> processRouteItems = processRouteItemMapper.selectList(new QueryWrapper<ProcessRouteItem>().lambda().eq(ProcessRouteItem::getRouteId, processRoute.getId()));
+//            // 鐢熸垚褰撳墠鏃ユ湡鐨勫墠缂�锛氬勾鏈堟棩
+//            String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+//            for (ProcessRouteItem processRouteItem : processRouteItems) {
+//                ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
+//                productProcessRouteItem.setProductModelId(salesLedgerProduct.getProductModelId());
+//                productProcessRouteItem.setProcessId(processRouteItem.getProcessId());
+//                productProcessRouteItem.setProductOrderId(productOrder.getId());
+//                productProcessRouteItem.setProductRouteId(productProcessRoute.getId());
+//                productProcessRouteItem.setDragSort(processRouteItem.getDragSort());
+//                int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
+//                if (insert > 0) {
+//                    // 鏌ヨ浠婃棩宸插瓨鍦ㄧ殑鏈�澶у伐鍗曞彿
+//                    ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectMax(datePrefix);
+//                    int sequenceNumber = 1; // 榛樿搴忓彿
+//                    if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
+//                        String lastNo = lastWorkOrder.getWorkOrderNo().toString();
+//                        if (lastNo.startsWith(datePrefix)) {
+//                            String seqStr = lastNo.substring(datePrefix.length());
+//                            try {
+//                                sequenceNumber = Integer.parseInt(seqStr) + 1;
+//                            } catch (NumberFormatException e) {
+//                                sequenceNumber = 1;
+//                            }
+//                        }
+//                    }
+//                    // 鐢熸垚瀹屾暣鐨勫伐鍗曞彿
+//                    String workOrderNoStr ="GD"+ String.format("%s%03d", datePrefix, sequenceNumber);
+//                    ProductWorkOrder productWorkOrder = new ProductWorkOrder();
+//                    productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
+//                    productWorkOrder.setProductOrderId(productOrder.getId());
+//                    productWorkOrder.setPlanQuantity(salesLedgerProduct.getQuantity());
+//                    productWorkOrder.setWorkOrderNo(workOrderNoStr);
+//                    productWorkOrder.setStatus(1);
+//
+//                    productWorkOrderMapper.insert(productWorkOrder);
+//                }
+//
+//            }
+//            productOrder.setRouteId(processRoute.getId());
+//            productOrderMapper.updateById(productOrder);
+//        }
     }
 
     /**
@@ -329,7 +377,7 @@
         //鎵归噺鏌ヨproductOrder
         List<ProductOrder> productOrders = productOrderMapper.selectList(
                 new LambdaQueryWrapper<ProductOrder>()
-                        .in(ProductOrder::getProductModelId, productIds)
+                        .in(ProductOrder::getSaleLedgerProductId, productIds)
         );
         if (!org.springframework.util.CollectionUtils.isEmpty(productOrders)) {
             List<Long> orderIds = productOrders.stream()
@@ -375,6 +423,13 @@
                                 new LambdaQueryWrapper<QualityInspect>()
                                         .in(QualityInspect::getProductMainId, productMainIds)
                         );
+                        //鍒犻櫎鍑哄簱璁板綍
+                        for (Long productMainId : productMainIds) {
+                            //鍒犻櫎鐢熶骇鍑哄簱璁板綍
+                            stockUtils.deleteStockOutRecord(productMainId, StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
+                            //鍒犻櫎鎶ュ簾鐨勫叆搴撹褰�
+                            stockUtils.deleteStockInRecord(productMainId, StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
+                        }
                         qualityInspects.forEach(qualityInspect -> {
                             //inspectState=1 宸叉彁浜� 涓嶈兘鍒犻櫎
                             if (qualityInspect.getInspectState() == 1) {
@@ -382,6 +437,8 @@
                             }
                         });
                         qualityInspectMapper.deleteByProductMainIds(productMainIds);
+                        salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
+                                .in(SalesLedgerProductionAccounting::getProductMainId, productMainIds));
                     }
 
                     // 鍒犻櫎鐢熶骇涓昏〃鏁版嵁
@@ -402,7 +459,7 @@
 
             // 鎵归噺鍒犻櫎productOrder
             productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
-                    .in(ProductOrder::getProductModelId, productIds));
+                    .in(ProductOrder::getSaleLedgerProductId, productIds));
         }
     }
 
@@ -425,7 +482,7 @@
         IPage<SalesLedgerProductDto> salesLedgerProductDtoIPage = salesLedgerProductMapper.listPagePurchaseLedger(page, salesLedgerProduct);
         salesLedgerProductDtoIPage.getRecords().forEach(item -> {
             // 鍒ゆ柇鐘舵��
-            if(item.getTaxInclusiveTotalPrice().compareTo(item.getInvoiceTotal()) == 0){
+            if(item.getTaxInclusiveTotalPrice().compareTo(item.getTicketsTotal()) == 0){
                 item.setStatusName("宸插畬鎴愪粯娆�");
             }else{
                 item.setStatusName("鏈畬鎴愪粯娆�");
@@ -471,7 +528,13 @@
     @Override
     public R judgmentInventory(SalesLedgerProduct salesLedgerProduct) {
         //鑾峰彇浜у搧鏈�鏂扮殑宸ヨ壓璺嚎
-        ProcessRoute processRoute = processRouteMapper.selectOne(new QueryWrapper<ProcessRoute>().lambda().eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId()).orderByDesc(ProcessRoute::getCreateTime).last("LIMIT 1"));
+        ProcessRoute processRoute = processRouteMapper.selectOne(
+                new QueryWrapper<ProcessRoute>()
+                        .and(wrapper -> wrapper.eq("product_model_id", salesLedgerProduct.getProductModelId())
+                                .or()
+                                .apply("find_in_set({0}, product_model_ids)", salesLedgerProduct.getProductModelId()))
+                        .orderByDesc("create_time")
+                        .last("LIMIT 1"));
         if (processRoute == null) {
             return R.fail("璇峰厛璁剧疆宸ヨ壓璺嚎");
         }
@@ -482,10 +545,11 @@
         int count = 0;
         StringBuilder stringBuffer = new StringBuilder();
         for (ProductStructureDto productStructureDto : productStructureDtos) {
-            BigDecimal stockQuantity = stockUtils.getStockQuantity(productStructureDto.getProductModelId()).get("stockQuantity");
+            StockInventory stockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, productStructureDto.getProductModelId()));
+
             //鎵�闇�鏁伴噺
             BigDecimal multiply = salesLedgerProduct.getQuantity().multiply(productStructureDto.getUnitQuantity());
-            BigDecimal subtract =stockQuantity.subtract(multiply).divide(BigDecimal.ONE, 2, RoundingMode.CEILING);
+            BigDecimal subtract =stockInventory.getQualitity().subtract(stockInventory.getLockedQuantity()).subtract(multiply).divide(BigDecimal.ONE, 2, RoundingMode.CEILING);
             if (subtract.compareTo(BigDecimal.ZERO) <= 0) {
                 count++;
                 stringBuffer.append(productStructureDto.getProductName())

--
Gitblit v1.9.3