From f088078e626e16b28d69cdbcbf514b30f1dcefe7 Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期三, 22 四月 2026 11:51:58 +0800
Subject: [PATCH] refactor(production): 优化生产订单及工单号生成逻辑

---
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java           |   82 +++++--------
 src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java        |   37 +++++
 src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java         |   33 ++---
 src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java            |   64 ++++------
 src/main/java/com/ruoyi/production/service/ProductWorkOrderService.java                 |    9 +
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java                  |    8 +
 src/main/java/com/ruoyi/common/utils/StringUtils.java                                   |   35 +++++
 pom.xml                                                                                 |    8 +
 src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java |   28 +---
 9 files changed, 170 insertions(+), 134 deletions(-)

diff --git a/pom.xml b/pom.xml
index e5cea04..bdcdf68 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,7 +39,7 @@
         <tomcat.version>9.0.102</tomcat.version>
         <minio.version>8.4.3</minio.version>
         <okhttp.version>4.9.0</okhttp.version>
-        <hutool.version>5.8.18</hutool.version>
+        <hutool.version>5.8.38</hutool.version>
         <logback.version>1.2.13</logback.version>
         <spring-security.version>5.7.12</spring-security.version>
         <spring-framework.version>5.3.39</spring-framework.version>
@@ -325,7 +325,11 @@
             <groupId>com.fasterxml.jackson.datatype</groupId>
             <artifactId>jackson-datatype-jsr310</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>com.belerweb</groupId>
+            <artifactId>pinyin4j</artifactId>
+            <version>2.5.1</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/src/main/java/com/ruoyi/common/utils/StringUtils.java b/src/main/java/com/ruoyi/common/utils/StringUtils.java
index 4e9b245..5e13807 100644
--- a/src/main/java/com/ruoyi/common/utils/StringUtils.java
+++ b/src/main/java/com/ruoyi/common/utils/StringUtils.java
@@ -6,6 +6,9 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.pinyin.PinyinUtil;
 import org.springframework.util.AntPathMatcher;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.text.StrFormatter;
@@ -726,4 +729,36 @@
         // 鐢ㄧ┖鏍艰ˉ榻�
         return String.format("%-" + length + "s", str);
     }
+
+
+    public static boolean containsChinese(String str) {
+        if (str == null) return false;
+        for (char c : str.toCharArray()) {
+            if (Character.UnicodeScript.of(c) == Character.UnicodeScript.HAN) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static String getProcessNo(String processName) {
+        if (StrUtil.isBlank(processName)) {
+            return "";
+        }
+
+        // 鍒ゆ柇鏄惁鍖呭惈涓枃
+        if (StringUtils.containsChinese(processName)) {
+            // 涓枃锛氭嫾闊抽瀛楁瘝
+            return StrUtil.toUpperCase(PinyinUtil.getFirstLetter(processName, ""));
+        } else {
+            // 鑻辨枃锛氬彇澶у啓瀛楁瘝 鐩墠宸ュ簭鍚嶇О娌℃湁鑻辨枃鐨勫舰寮� 鍙兘澶勭悊ExxxBxxx
+            StringBuilder sb = new StringBuilder();
+            for (char c : processName.toCharArray()) {
+                if (Character.isUpperCase(c)) {
+                    sb.append(c);
+                }
+            }
+            return sb.toString();
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/production/service/ProductWorkOrderService.java b/src/main/java/com/ruoyi/production/service/ProductWorkOrderService.java
index b092a40..e8a2aed 100644
--- a/src/main/java/com/ruoyi/production/service/ProductWorkOrderService.java
+++ b/src/main/java/com/ruoyi/production/service/ProductWorkOrderService.java
@@ -18,4 +18,13 @@
     void down(HttpServletResponse response, ProductWorkOrder productWorkOrder);
 
     ProductWorkOrderDto getProductWorkOrderById(@NotNull Long id);
+
+    /**
+     * 鑷姩鐢熸垚鐢熶骇宸ュ崟鍙�
+     * @param datePrefix yyyyMMdd 鏉ヨ幏鍙栧綋鏃ョ殑鏁伴噺
+     * @param processName 宸ュ簭鍚嶇О
+     * @param npsNo 鐢熶骇璁㈠崟鍙�
+     * @return String
+     */
+    String generateProductWorkOrder(String datePrefix, String processName,String npsNo);
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
index 8a1099c..81ac09e 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -7,16 +7,16 @@
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.production.dto.ProductOrderDto;
 import com.ruoyi.production.dto.ProductStructureDto;
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.production.pojo.*;
 import com.ruoyi.production.service.ProductOrderService;
+import com.ruoyi.production.service.ProductProcessService;
+import com.ruoyi.production.service.ProductWorkOrderService;
 import com.ruoyi.quality.mapper.QualityInspectMapper;
-import com.ruoyi.quality.pojo.QualityInspect;
+import lombok.RequiredArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -24,44 +24,37 @@
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 @Service
+@RequiredArgsConstructor
 public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, ProductOrder> implements ProductOrderService {
 
+    private final ProductWorkOrderService productWorkOrderService;
+    private final ProductProcessService productProcessService;
     @Autowired
     private ProductOrderMapper productOrderMapper;
-
     @Autowired
     private ProcessRouteMapper processRouteMapper;
-
     @Autowired
     private ProductProcessRouteMapper productProcessRouteMapper;
-
     @Autowired
     private ProcessRouteItemMapper processRouteItemMapper;
-
     @Autowired
     private ProductProcessRouteItemMapper productProcessRouteItemMapper;
-
     @Autowired
     private ProductWorkOrderMapper productWorkOrderMapper;
-
     @Autowired
     private ProductionProductMainMapper productionProductMainMapper;
-
     @Autowired
     private ProductionProductOutputMapper productionProductOutputMapper;
-
     @Autowired
     private ProductionProductInputMapper productionProductInputMapper;
-
     @Autowired
     private QualityInspectMapper qualityInspectMapper;
-
     @Autowired
     private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
-
     @Autowired
     private StockUtils stockUtils;
 
@@ -82,8 +75,12 @@
         productProcessRouteMapper.insert(productProcessRoute);
         //鏂板鐢熶骇璁㈠崟涓嬬殑宸ヨ壓璺嚎瀛愯〃
         List<ProcessRouteItem> processRouteItems = processRouteItemMapper.selectList(new QueryWrapper<ProcessRouteItem>().lambda().eq(ProcessRouteItem::getRouteId, processRoute.getId()));
+        Map<Long, ProductProcess> productProcessMap = productProcessService
+                .list(new LambdaQueryWrapper<ProductProcess>().in(ProductProcess::getId, processRouteItems.stream().map(ProcessRouteItem::getProcessId).collect(Collectors.toList())))
+                .stream()
+                .collect(Collectors.toMap(ProductProcess::getId, productProcess -> productProcess));
+
         // 鐢熸垚褰撳墠鏃ユ湡鐨勫墠缂�锛氬勾鏈堟棩
-        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
         for (ProcessRouteItem processRouteItem : processRouteItems) {
             ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
             productProcessRouteItem.setProductModelId(processRouteItem.getProductModelId());
@@ -93,28 +90,13 @@
             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());
                 ProductOrder order = productOrderMapper.selectById(productOrder.getId());
                 productWorkOrder.setPlanQuantity(order.getQuantity());
-                productWorkOrder.setWorkOrderNo(workOrderNoStr);
+                productWorkOrder.setWorkOrderNo(productWorkOrderService.generateProductWorkOrder(null, productProcessMap.getOrDefault(productProcessRouteItem.getProcessId(), new ProductProcess()).getName(), productOrder.getNpsNo()));
                 productWorkOrder.setStatus(1);
                 productWorkOrderMapper.insert(productWorkOrder);
             }
@@ -149,11 +131,11 @@
         //濡傛灉宸茬粡寮�濮嬬敓浜�,涓嶈兘鍒犻櫎
         //鏌ヨ鐢熶骇璁㈠崟涓嬬殑宸ュ崟
         List<ProductWorkOrder> productWorkOrders = productWorkOrderMapper.selectList(Wrappers.<ProductWorkOrder>lambdaQuery().in(ProductWorkOrder::getProductOrderId, ids));
-        if (productWorkOrders.size()>0){
+        if (productWorkOrders.size() > 0) {
             //鍒ゆ柇鏄惁鏈夋姤宸ユ暟鎹�
             List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(Wrappers.<ProductionProductMain>lambdaQuery()
                     .in(ProductionProductMain::getWorkOrderId, productWorkOrders.stream().map(ProductWorkOrder::getId).collect(Collectors.toList())));
-            if (productionProductMains.size()>0){
+            if (productionProductMains.size() > 0) {
                 throw new RuntimeException("鐢熶骇璁㈠崟宸茬粡寮�濮嬬敓浜�,涓嶈兘鍒犻櫎");
             }
             //鍒犻櫎宸ュ崟
@@ -184,8 +166,16 @@
     }
 
     public String generateNextOrderNo(String datePrefix) {
-        String maxOrderNo = getMaxOrderNoByDate(datePrefix);
+        return "SC" + datePrefix + formatOrderSequence(datePrefix);
+    }
+
+    public String generateNextOrderByContractNo(String datePrefix, String contractNo) {
+        return contractNo + formatOrderSequence(datePrefix);
+    }
+
+    private String formatOrderSequence(String datePrefix) {
         int sequence = 1; // 榛樿璧峰搴忓彿
+        String maxOrderNo = getMaxOrderNoByDate(datePrefix);
         if (maxOrderNo != null && !maxOrderNo.isEmpty()) {
             // 鎻愬彇娴佹按鍙烽儴鍒嗭紙鍋囪鏍煎紡涓� SC + 鏃ユ湡 + 娴佹按鍙凤級
             String sequenceStr = maxOrderNo.substring(("SC" + datePrefix).length());
@@ -196,9 +186,7 @@
                 sequence = 1;
             }
         }
-        // 鐢熸垚鏂拌鍗曞彿
-        return "SC" + datePrefix + String.format("%04d", sequence);
+        return String.format("%04d", sequence);
     }
-
 
 }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java
index 19f5f61..081ff3b 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java
@@ -10,6 +10,8 @@
 import com.ruoyi.production.mapper.*;
 import com.ruoyi.production.pojo.*;
 import com.ruoyi.production.service.ProductProcessRouteItemService;
+import com.ruoyi.production.service.ProductProcessService;
+import com.ruoyi.production.service.ProductWorkOrderService;
 import com.ruoyi.production.service.ProductionProductMainService;
 import com.ruoyi.quality.mapper.QualityInspectMapper;
 import com.ruoyi.quality.pojo.QualityInspect;
@@ -51,6 +53,9 @@
 
     private ProductOrderMapper productOrderMapper;
 
+    private final ProductWorkOrderService productWorkOrderService;
+
+    private final ProductProcessService productProcessService;
 
 
     @Override
@@ -131,31 +136,16 @@
     @Override
     public R addRouteItem(ProductProcessRouteItem productProcessRouteItem) {
         ProductOrder productOrder = productOrderMapper.selectById(productProcessRouteItem.getProductOrderId());
+        ProductProcess productProcess = productProcessService.getById(productProcessRouteItem.getProcessId());
         int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
-        // 鐢熸垚褰撳墠鏃ユ湡鐨勫墠缂�锛氬勾鏈堟棩
-        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+
         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(productProcessRouteItem.getProductOrderId());
             productWorkOrder.setPlanQuantity(productOrder.getQuantity());
-            productWorkOrder.setWorkOrderNo(workOrderNoStr);
+            productWorkOrder.setWorkOrderNo(productWorkOrderService.generateProductWorkOrder(null,productProcess.getName(),productOrder.getNpsNo()));
             productWorkOrder.setStatus(1);
             productWorkOrderMapper.insert(productWorkOrder);
         }
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java
index 2c355fc..5272932 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductWorkOrderServiceImpl.java
@@ -1,6 +1,9 @@
 package com.ruoyi.production.service.impl;
 
 
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.pinyin.PinyinUtil;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -10,6 +13,7 @@
 import com.deepoove.poi.data.PictureRenderData;
 import com.deepoove.poi.data.Pictures;
 import com.ruoyi.common.utils.MatrixToImageWriter;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.production.dto.ProductWorkOrderDto;
 import com.ruoyi.production.mapper.ProductWorkOrderFileMapper;
 import com.ruoyi.production.mapper.ProductWorkOrderMapper;
@@ -25,6 +29,8 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URLEncoder;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -35,7 +41,7 @@
 public class ProductWorkOrderServiceImpl extends ServiceImpl<ProductWorkOrderMapper, ProductWorkOrder> implements ProductWorkOrderService {
 
     @Autowired
-    private ProductWorkOrderMapper productWorkOrdermapper;
+    private ProductWorkOrderMapper productWorkOrderMapper;
     @Autowired
     private ProductWorkOrderFileMapper productWorkOrderFileMapper;
 
@@ -44,17 +50,17 @@
 
     @Override
     public IPage<ProductWorkOrderDto> listPage(Page<ProductWorkOrderDto> page, ProductWorkOrderDto productWorkOrder) {
-        return productWorkOrdermapper.pageProductWorkOrder(page, productWorkOrder);
+        return productWorkOrderMapper.pageProductWorkOrder(page, productWorkOrder);
     }
 
     @Override
     public int updateProductWorkOrder(ProductWorkOrderDto productWorkOrderDto) {
-        return productWorkOrdermapper.updateById(productWorkOrderDto);
+        return productWorkOrderMapper.updateById(productWorkOrderDto);
     }
 
     @Override
     public void down(HttpServletResponse response, ProductWorkOrder productWorkOrder) {
-        ProductWorkOrderDto productWorkOrderDto = productWorkOrdermapper.getProductWorkOrderFlowCard(productWorkOrder.getId());
+        ProductWorkOrderDto productWorkOrderDto = productWorkOrderMapper.getProductWorkOrderFlowCard(productWorkOrder.getId());
         String codePath;
         try {
             codePath = new MatrixToImageWriter().code(productWorkOrderDto.getId().toString(), tempDir);
@@ -112,8 +118,29 @@
 
     @Override
     public ProductWorkOrderDto getProductWorkOrderById(Long id) {
-        return productWorkOrdermapper.getProductWorkOrderFlowCard(id);
+        return productWorkOrderMapper.getProductWorkOrderFlowCard(id);
     }
 
+    @Override
+    public String generateProductWorkOrder(String datePrefix,String processName, String npsNo) {
+        datePrefix = StrUtil.isBlank(datePrefix) ? LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) : datePrefix;
+        processName = StrUtil.isBlank(processName) ? "鏈煡" : processName;
+        Assert.notNull(npsNo, "鐢熶骇璁㈠崟鍙风紪鍙蜂笉鑳戒负绌�");
+        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 processPinyin = StringUtils.getProcessNo(processName);
+            return StrUtil.format("{}{}{}",processPinyin,npsNo,String.format("%03d", sequenceNumber));
+    }
 
 }
diff --git a/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java b/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
index 2a5c9e9..a716575 100644
--- a/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
+++ b/src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
@@ -1,6 +1,7 @@
 package com.ruoyi.quality.service.impl;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
@@ -19,6 +20,8 @@
 import com.ruoyi.production.mapper.ProductionProductMainMapper;
 import com.ruoyi.production.pojo.*;
 import com.ruoyi.production.service.ProductOrderService;
+import com.ruoyi.production.service.ProductProcessService;
+import com.ruoyi.production.service.ProductWorkOrderService;
 import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
 import com.ruoyi.quality.pojo.QualityInspect;
 import com.ruoyi.quality.pojo.QualityUnqualified;
@@ -33,12 +36,15 @@
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @AllArgsConstructor
 @Service
 public class QualityUnqualifiedServiceImpl extends ServiceImpl<QualityUnqualifiedMapper, QualityUnqualified> implements IQualityUnqualifiedService {
 
     private final StockUtils stockUtils;
+    private final ProductWorkOrderService productWorkOrderService;
     private QualityUnqualifiedMapper qualityUnqualifiedMapper;
     private IQualityInspectService qualityInspectService;
     private ProductOrderService productOrderService;
@@ -47,6 +53,7 @@
     private ProductProcessRouteItemMapper productProcessRouteItemMapper;
     private ProductWorkOrderMapper productWorkOrderMapper;
     private StockUninventoryService stockUninventoryService;
+    private final ProductProcessService productProcessService;
 
     @Override
     public IPage<QualityUnqualified> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) {
@@ -89,8 +96,12 @@
                         productProcessRouteMapper.insert(newProcessRoute);
                         //鏂板鐢熶骇璁㈠崟涓嬬殑宸ヨ壓璺嚎瀛愯〃
                         List<ProductProcessRouteItem> processRouteItems = productProcessRouteItemMapper.selectList(new QueryWrapper<ProductProcessRouteItem>().lambda().eq(ProductProcessRouteItem::getProductRouteId, productProcessRoute.getId()));
-                        // 鐢熸垚褰撳墠鏃ユ湡鐨勫墠缂�锛氬勾鏈堟棩
-                        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+
+                        Map<Long, ProductProcess> productProcessMap = productProcessService
+                                .list(new LambdaQueryWrapper<ProductProcess>().in(ProductProcess::getId, processRouteItems.stream().map(ProductProcessRouteItem::getProcessId).collect(Collectors.toList())))
+                                .stream()
+                                .collect(Collectors.toMap(ProductProcess::getId, productProcess -> productProcess));
+
                         for (ProductProcessRouteItem processRouteItem : processRouteItems) {
                             ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
                             BeanUtils.copyProperties(processRouteItem, productProcessRouteItem);
@@ -98,27 +109,11 @@
                             productProcessRouteItem.setProductRouteId(newProcessRoute.getId());
                             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 = "FG" + String.format("%s%03d", datePrefix, sequenceNumber);
                                 ProductWorkOrder productWorkOrder = new ProductWorkOrder();
                                 productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
                                 productWorkOrder.setProductOrderId(order.getId());
                                 productWorkOrder.setPlanQuantity(order.getQuantity());
-                                productWorkOrder.setWorkOrderNo(workOrderNoStr);
+                                productWorkOrder.setWorkOrderNo("FG"+productWorkOrderService.generateProductWorkOrder(null, productProcessMap.getOrDefault(productProcessRouteItem.getProcessId(), new ProductProcess()).getName(), productOrder.getNpsNo()));
                                 productWorkOrder.setStatus(1);
                                 productWorkOrderMapper.insert(productWorkOrder);
                             }
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 71e7f84..8b84e12 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -6,13 +6,15 @@
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
 import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
+import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
 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.ProductProcessService;
+import com.ruoyi.production.service.ProductWorkOrderService;
 import com.ruoyi.production.service.impl.ProductOrderServiceImpl;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
@@ -56,24 +58,18 @@
 @AllArgsConstructor
 public class SalesLedgerProductServiceImpl extends ServiceImpl<SalesLedgerProductMapper, SalesLedgerProduct> implements ISalesLedgerProductService {
 
+    private final ProductWorkOrderService productWorkOrderService;
+    private final ProductProcessService productProcessService;
     private SalesLedgerProductMapper salesLedgerProductMapper;
     private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
-
     private SalesLedgerMapper salesLedgerMapper;
-
     private PurchaseLedgerMapper purchaseLedgerMapper;
-
     private ProductOrderMapper productOrderMapper;
-
     private ProcessRouteItemMapper processRouteItemMapper;
-
     private ProductProcessRouteItemMapper productProcessRouteItemMapper;
-
     private InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
-
     private ProcessRouteMapper processRouteMapper;
     private ProductProcessRouteMapper productProcessRouteMapper;
-
     private ProductWorkOrderMapper productWorkOrderMapper;
     private ProductionProductMainMapper productionProductMainMapper;
     private ProductionProductOutputMapper productionProductOutputMapper;
@@ -81,11 +77,7 @@
     private QualityInspectMapper qualityInspectMapper;
     private ShippingInfoMapper shippingInfoMapper;
     private ShippingInfoServiceImpl shippingInfoService;
-
     private StockUtils stockUtils;
-
-
-
     @Autowired
     private ProductStructureMapper productStructureMapper;
     @Autowired
@@ -104,14 +96,14 @@
 //        queryWrapper.eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerProduct.getSalesLedgerId())
 //                .eq(SalesLedgerProduct::getType, salesLedgerProduct.getType());
         List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectSalesLedgerProductList(salesLedgerProduct);
-        if(!CollectionUtils.isEmpty(salesLedgerProducts)){
+        if (!CollectionUtils.isEmpty(salesLedgerProducts)) {
             salesLedgerProducts.forEach(item -> {
                 // 鍙戣揣淇℃伅
                 ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
                         .eq(ShippingInfo::getSalesLedgerProductId, item.getId())
                         .orderByDesc(ShippingInfo::getCreateTime)
                         .last("limit 1"));
-                if(shippingInfo != null){
+                if (shippingInfo != null) {
                     item.setShippingDate(shippingInfo.getShippingDate());
                     item.setShippingCarNumber(shippingInfo.getShippingCarNumber());
                     item.setShippingStatus(shippingInfo.getStatus());
@@ -131,8 +123,8 @@
                     BigDecimal noInvoiceNum = BigDecimal.ZERO;
                     BigDecimal noInvoiceAmount = BigDecimal.ZERO;
                     for (InvoiceRegistrationProductDto registrationProductDto : invoiceRegistrationProductDtoList) {
-                        if(ledgerProduct.getId().intValue() == registrationProductDto.getSalesLedgerProductId()){
-                            invoiceNum =  invoiceNum.add(registrationProductDto.getInvoiceNum());
+                        if (ledgerProduct.getId().intValue() == registrationProductDto.getSalesLedgerProductId()) {
+                            invoiceNum = invoiceNum.add(registrationProductDto.getInvoiceNum());
                             invoiceAmount = invoiceAmount.add(registrationProductDto.getInvoiceAmount());
                         }
                     }
@@ -166,7 +158,7 @@
         //鍒犻櫎鍙戣揣淇℃伅
         List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                 .in(ShippingInfo::getSalesLedgerProductId, Arrays.asList(ids)));
-        if(!CollectionUtils.isEmpty(shippingInfos)){
+        if (!CollectionUtils.isEmpty(shippingInfos)) {
             shippingInfoService.delete(shippingInfos.stream().map(ShippingInfo::getId).collect(Collectors.toList()));
         }
 
@@ -203,12 +195,12 @@
     @Transactional(rollbackFor = Exception.class)
     public int addOrUpdateSalesLedgerProduct(SalesLedgerProduct salesLedgerProduct) {
         // 寰呭洖娆撅紝浠樻
-        if(salesLedgerProduct.getType().equals(1)){
+        if (salesLedgerProduct.getType().equals(1)) {
             salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getInvoiceTotal()));
             //鏈紑绁ㄦ暟閲�+閲戦
             salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
             salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
-        }else{
+        } else {
             salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getTaxInclusiveTotalPrice().subtract(salesLedgerProduct.getTicketsTotal()));
             // 鏈潵绁ㄦ暟閲�+閲戦
             salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity());
@@ -266,11 +258,14 @@
      * 鏂板鐢熶骇鏁版嵁
      */
     public void addProductionData(SalesLedgerProduct salesLedgerProduct) {
+
+        SalesLedger salesLedger = salesLedgerMapper.selectById(salesLedgerProduct.getSalesLedgerId());
+
         ProductOrder productOrder = new ProductOrder();
         productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
         productOrder.setProductModelId(salesLedgerProduct.getProductModelId());
         productOrder.setSaleLedgerProductId(salesLedgerProduct.getId());
-        String string = productOrderServiceImpl.generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
+        String string = productOrderServiceImpl.generateNextOrderByContractNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")), salesLedger.getSalesContractNo());
         productOrder.setNpsNo(string);
         productOrder.setQuantity(salesLedgerProduct.getQuantity());//闇�姹傛暟閲�
         productOrder.setCompleteQuantity(BigDecimal.ZERO);//瀹屾垚鏁伴噺
@@ -279,7 +274,7 @@
         List<ProcessRoute> processRoutes = processRouteMapper.selectList(new QueryWrapper<ProcessRoute>().lambda()
                 .eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId())
                 .orderByDesc(ProcessRoute::getCreateTime));
-        if (processRoutes.size()>0){
+        if (processRoutes.size() > 0) {
             ProcessRoute processRoute = processRoutes.get(0);
             //鏂板鐢熶骇璁㈠崟宸ヨ壓璺嚎涓昏〃
             ProductProcessRoute productProcessRoute = new ProductProcessRoute();
@@ -290,8 +285,12 @@
             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"));
+
+            Map<Long, ProductProcess> productProcessMap = productProcessService
+                    .list(new LambdaQueryWrapper<ProductProcess>().in(ProductProcess::getId, processRouteItems.stream().map(ProcessRouteItem::getProcessId).collect(Collectors.toList())))
+                    .stream()
+                    .collect(Collectors.toMap(ProductProcess::getId, productProcess -> productProcess));
+
             for (ProcessRouteItem processRouteItem : processRouteItems) {
                 ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
                 productProcessRouteItem.setProductModelId(processRouteItem.getProductModelId());
@@ -301,27 +300,11 @@
                 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.setWorkOrderNo(productWorkOrderService.generateProductWorkOrder(null, productProcessMap.getOrDefault(productProcessRouteItem.getProcessId(),new ProductProcess()).getName(), productOrder.getNpsNo()));
                     productWorkOrder.setStatus(1);
 
                     productWorkOrderMapper.insert(productWorkOrder);
@@ -431,9 +414,9 @@
         IPage<SalesLedgerProductDto> salesLedgerProductDtoIPage = salesLedgerProductMapper.listPage(page, salesLedgerProduct);
         salesLedgerProductDtoIPage.getRecords().forEach(item -> {
             // 鍒ゆ柇鐘舵��
-            if(item.getTaxInclusiveTotalPrice().compareTo(item.getInvoiceTotal()) == 0){
+            if (item.getTaxInclusiveTotalPrice().compareTo(item.getInvoiceTotal()) == 0) {
                 item.setStatusName("宸插畬鎴愪粯娆�");
-            }else{
+            } else {
                 item.setStatusName("鏈畬鎴愪粯娆�");
             }
         });
@@ -445,9 +428,9 @@
         IPage<SalesLedgerProductDto> salesLedgerProductDtoIPage = salesLedgerProductMapper.listPagePurchaseLedger(page, salesLedgerProduct);
         salesLedgerProductDtoIPage.getRecords().forEach(item -> {
             // 鍒ゆ柇鐘舵��
-            if(item.getTaxInclusiveTotalPrice().compareTo(item.getTicketsTotal()) == 0){
+            if (item.getTaxInclusiveTotalPrice().compareTo(item.getTicketsTotal()) == 0) {
                 item.setStatusName("宸插畬鎴愪粯娆�");
-            }else{
+            } else {
                 item.setStatusName("鏈畬鎴愪粯娆�");
             }
         });
@@ -488,6 +471,7 @@
             throw new RuntimeException("鍔ㄦ�佹洿鏂颁富琛ㄩ噾棰濆け璐�", e);
         }
     }
+
     @Override
     public R judgmentInventory(SalesLedgerProduct salesLedgerProduct) {
         //鑾峰彇浜у搧鏈�鏂扮殑宸ヨ壓璺嚎
@@ -495,7 +479,7 @@
         if (processRoute == null) {
             return R.fail("璇峰厛璁剧疆宸ヨ壓璺嚎");
         }
-        List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomId(processRoute.getBomId(),false);
+        List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomId(processRoute.getBomId(), false);
         if (productStructureDtos.isEmpty()) {
             return R.fail("璇峰厛璁剧疆浜у搧缁撴瀯");
         }
@@ -506,7 +490,7 @@
 
             //鎵�闇�鏁伴噺
             BigDecimal multiply = salesLedgerProduct.getQuantity().multiply(productStructureDto.getUnitQuantity());
-            BigDecimal subtract =stockInventory.getQualitity().subtract(stockInventory.getLockedQuantity()).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())
@@ -517,9 +501,9 @@
                         .append(System.lineSeparator());
             }
         }
-        if (count>0) {
+        if (count > 0) {
             return R.fail(stringBuffer.toString());
-        }else {
+        } else {
             return R.ok();
         }
     }
diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
index 60e7fd5..07ad60a 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -664,12 +664,13 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int addOrUpdateSalesLedger(SalesLedgerDto salesLedgerDto) {
-        try {
             // 1. 鏍¢獙瀹㈡埛淇℃伅
             CustomerPrivatePoolDto customer = customerPrivatePoolMapper.selectInfo(salesLedgerDto.getCustomerId());
             if (customer == null) {
                 throw new BaseException("瀹㈡埛涓嶅瓨鍦�");
             }
+            // 蹇呴』濉啓閿�鍞悎鍚屽彿
+//            Assert.notNull(salesLedgerDto.getSalesContractNo(), "閿�鍞悎鍚屽彿涓嶈兘涓虹┖");
 
             // 2. DTO杞珽ntity
             SalesLedger salesLedger = convertToEntity(salesLedgerDto);
@@ -677,10 +678,12 @@
             salesLedger.setTenantId(customer.getTenantId());
             // 3. 鏂板鎴栨洿鏂颁富琛�
             if (salesLedger.getId() == null) {
-                String contractNo = generateSalesContractNoBy8Date();
+                // 涓虹┖ 鑷姩鐢熸垚
+                String contractNo =StrUtil.isBlank(salesLedgerDto.getSalesContractNo())? generateSalesContractNoBy8Date():salesLedgerDto.getSalesContractNo();
                 salesLedger.setSalesContractNo(contractNo);
                 salesLedgerMapper.insert(salesLedger);
             } else {
+                salesLedger.setSalesContractNo(null);
                 salesLedgerMapper.updateById(salesLedger);
             }
 
@@ -696,6 +699,7 @@
                         SalesLedger.class
                 );
             }
+        try {
 
             // 5. 杩佺Щ涓存椂鏂囦欢鍒版寮忕洰褰�
             if (salesLedgerDto.getTempFileIds() != null && !salesLedgerDto.getTempFileIds().isEmpty()) {

--
Gitblit v1.9.3