From bdb10f17dd56fdb8dd8e3dca897c5cfb5e40a75d Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期二, 16 六月 2026 14:01:12 +0800
Subject: [PATCH] Merge branch 'dev_New_pro' of http://114.132.189.42:9002/r/product-inventory-management-after into dev_New_pro

---
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java |    4 
 src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java                |   72 ++++++++-----
 src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java |  189 +++++++++++++++++++++++++++++++++++++
 3 files changed, 233 insertions(+), 32 deletions(-)

diff --git a/src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java b/src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java
index e52ab8e..6e81263 100644
--- a/src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java
+++ b/src/main/java/com/ruoyi/mock/prompt/MockDataPrompt.java
@@ -19,10 +19,11 @@
             1. 杈撳嚭蹇呴』鏄函JSON鏁扮粍锛屼笉瑕佺敤markdown浠g爜鍧楀寘瑁癸紝涓嶈鏈変换浣曞叾浠栨枃瀛�
             2. 姣忎釜JSON瀵硅薄蹇呴』鍖呭惈 "entity" 瀛楁锛屽�间负瀹炰綋绫诲瀷鍚�
             3. 鏁版嵁鍐呭瑕佺鍚堟寚瀹氳涓氱殑鐗瑰緛锛堝叕鍙稿悕绉般�佷骇鍝佸悕绉般�佽仈绯讳汉绛夎鍍忚琛屼笟鐨勶級
-            4. 鏃ユ湡瀛楁鍦ㄦ寚瀹氱殑鏃堕棿鑼冨洿鍐呴殢鏈哄垎甯�
+            4. 鎵�鏈夋棩鏈熷瓧娈靛繀椤诲湪鎸囧畾鐨勬椂闂磋寖鍥村唴锛屼弗绂佷娇鐢ㄨ寖鍥翠箣澶栫殑鏃ユ湡
             5. 閲戦銆佹暟閲忕瓑鏁板�煎瓧娈佃鍚堢悊
             6. 鍚屼竴妯″潡鍐呯殑瀹炰綋涔嬮棿瑕佹湁寮曠敤鍏崇郴锛堝閿�鍞彴璐﹀紩鐢ㄥ鎴峰悕绉帮級
             7. 鎵�鏈夊瓧绗︿覆瀛楁涓嶈浣跨敤emoji鎴栫壒娈妘nicode瀛楃
+            8. 鍚堝悓缂栧彿銆佹壒鍙风瓑鍖呭惈鏃ユ湡鐨勫瓧娈碉紝蹇呴』浣跨敤鏃堕棿鑼冨洿鍐呯殑鏃ユ湡锛屼笉瑕佷娇鐢ㄧず渚嬩腑鐨勫叿浣撴棩鏈�
             """;
     }
 
@@ -55,13 +56,13 @@
             sb.append(buildPurchasePrompt(countMin, countMax, dateStart, dateEnd));
         }
         if (modules.contains("quality")) {
-            sb.append(buildQualityPrompt(countMin, countMax));
+            sb.append(buildQualityPrompt(countMin, countMax, dateStart));
         }
         if (modules.contains("production")) {
             sb.append(buildProductionPrompt(countMin, countMax, dateStart, dateEnd));
         }
         if (modules.contains("stock")) {
-            sb.append(buildStockPrompt(countMin, countMax));
+            sb.append(buildStockPrompt(countMin, countMax, dateStart));
         }
 
         sb.append("\n璇风洿鎺ヨ緭鍑篔SON鏁扮粍锛屼笉瑕佹湁浠讳綍鍏朵粬鍐呭:");
@@ -70,7 +71,7 @@
 
     private static String buildSalesPrompt(int min, int max, String dateStart, String dateEnd) {
         return """
-            閿�鍞ā鍧� - 鎸変互涓嬫牸寮忕敓鎴�:
+            閿�鍞ā鍧� - 鎸変互涓嬫牸寮忕敓鎴愶紙娉ㄦ剰锛氱ず渚嬩腑鐨勬棩鏈熶粎浣滄牸寮忓弬鑰冿紝瀹為檯鏃ユ湡蹇呴』鍦� %s ~ %s 鑼冨洿鍐咃級:
             {
               "entity": "customer",
               "customerName": "XX绉戞妧鏈夐檺鍏徃",
@@ -78,19 +79,26 @@
               "contactPerson": "寮犱笁",
               "contactPhone": "13800138000",
               "companyAddress": "XX鐪乆X甯俋X鍖篨X璺疿X鍙�",
-              "taxpayerIdentificationNumber": "91110108XXXXXXXXXX"
+              "companyPhone": "0513-XXXXXXXX",
+              "taxpayerIdentificationNumber": "91110108XXXXXXXXXX",
+              "maintainer": "鏉庡洓",
+              "maintenanceTime": "%s",
+              "bankAccount": "622202XXXXXXXXXXXX",
+              "basicBankAccount": "XX閾惰XX鏀",
+              "bankCode": "308100XXXXXX"
             }
             {
               "entity": "salesLedger",
               "customerName": "寮曠敤涓婇潰鐢熸垚鐨勫鎴峰悕绉�",
-              "salesContractNo": "XS-20260601-001",
+              "salesContractNo": "XS-骞存湀鏃�-搴忓彿",
               "projectName": "XX椤圭洰",
-              "entryDate": "2026-06-01",
+              "entryDate": "%s",
+              "entryPerson": "寮犱笁",
               "salesman": "閿�鍞憳濮撳悕",
               "contractAmount": 50000.00,
               "paymentMethod": "鏈堢粨30澶�",
-              "executionDate": "2026-06-01",
-              "deliveryDate": "2026-07-01",
+              "executionDate": "%s",
+              "deliveryDate": "%s",
               "type": 1,
               "productData": [
                 {
@@ -99,20 +107,22 @@
                   "quantity": 100,
                   "taxInclusiveUnitPrice": 500.00,
                   "taxInclusiveTotalPrice": 50000.00,
+                  "taxExclusiveTotalPrice": 44247.79,
                   "taxRate": 13.00,
                   "unit": "浠�",
                   "type": 1
                 }
               ]
             }
-            瀹㈡埛鍚嶇О瑕佸儚鎸囧畾琛屼笟鐨勫叕鍙革紝鍚堝悓缂栧彿鏍煎紡XS-骞存湀鏃�-搴忓彿锛岄噾棰濆悎鐞嗐��
+            瀹㈡埛鍚嶇О瑕佸儚鎸囧畾琛屼笟鐨勫叕鍙革紝鍚堝悓缂栧彿鏍煎紡XS-骞存湀鏃�-搴忓彿锛堝勾鏈堟棩鍙杄ntryDate鐨勬棩鏈燂級锛岄噾棰濆悎鐞嗐��
+            娉ㄦ剰 taxExclusiveTotalPrice 鏄笉鍚◣鎬讳环锛岄渶瑕佹牴鎹惈绋庢�讳环鍜岀◣鐜囪绠楋紙=鍚◣鎬讳环/(1+绋庣巼/100)锛夈��
             鏃ユ湡鑼冨洿: %s ~ %s锛屾瘡绉嶅疄浣撶敓鎴�%d-%d鏉°��
-            """.formatted(dateStart, dateEnd, min, max);
+            """.formatted(dateStart, dateEnd, dateStart, dateStart, dateStart, dateEnd, dateStart, dateEnd, min, max);
     }
 
     private static String buildPurchasePrompt(int min, int max, String dateStart, String dateEnd) {
         return """
-            閲囪喘妯″潡 - 鎸変互涓嬫牸寮忕敓鎴�:
+            閲囪喘妯″潡 - 鎸変互涓嬫牸寮忕敓鎴愶紙娉ㄦ剰锛氱ず渚嬩腑鐨勬棩鏈熶粎浣滄牸寮忓弬鑰冿紝瀹為檯鏃ユ湡蹇呴』鍦� %s ~ %s 鑼冨洿鍐咃級:
             {
               "entity": "supplier",
               "supplierName": "XX鍘熸潗鏂欐湁闄愬叕鍙�",
@@ -120,6 +130,7 @@
               "contactUserName": "鏉庡洓",
               "contactUserPhone": "13900139000",
               "companyAddress": "XX鐪乆X甯俋X鍖篨X璺疿X鍙�",
+              "companyPhone": "0513-XXXXXXXX",
               "taxpayerIdentificationNum": "91110108XXXXXXXXXX",
               "bankAccountName": "XX閾惰XX鏀",
               "bankAccountNum": "622202XXXXXXXXXXXX",
@@ -128,12 +139,12 @@
             {
               "entity": "purchaseLedger",
               "supplierName": "寮曠敤涓婇潰鐢熸垚鐨勪緵搴斿晢鍚嶇О",
-              "purchaseContractNumber": "CG-20260601-001",
+              "purchaseContractNumber": "CG-骞存湀鏃�-搴忓彿",
               "projectName": "XX閲囪喘椤圭洰",
-              "entryDate": "2026-06-01",
+              "entryDate": "%s",
               "contractAmount": 30000.00,
               "paymentMethod": "璐у埌浠樻",
-              "executionDate": "2026-06-01",
+              "executionDate": "%s",
               "productData": [
                 {
                   "productId": 1,
@@ -141,73 +152,76 @@
                   "quantity": 50,
                   "taxInclusiveUnitPrice": 600.00,
                   "taxInclusiveTotalPrice": 30000.00,
+                  "taxExclusiveTotalPrice": 26548.67,
                   "taxRate": 13.00,
                   "unit": "浠�",
                   "type": 2
                 }
               ]
             }
-            渚涘簲鍟嗗悕绉拌鍍忔寚瀹氳涓氱殑渚涘簲鍟嗭紝鍚堝悓缂栧彿鏍煎紡CG-骞存湀鏃�-搴忓彿銆�
+            渚涘簲鍟嗗悕绉拌鍍忔寚瀹氳涓氱殑渚涘簲鍟嗭紝鍚堝悓缂栧彿鏍煎紡CG-骞存湀鏃�-搴忓彿锛堝勾鏈堟棩鍙杄ntryDate鐨勬棩鏈燂級銆�
+            娉ㄦ剰 taxExclusiveTotalPrice 鏄笉鍚◣鎬讳环锛岄渶瑕佹牴鎹惈绋庢�讳环鍜岀◣鐜囪绠楋紙=鍚◣鎬讳环/(1+绋庣巼/100)锛夈��
             鏃ユ湡鑼冨洿: %s ~ %s锛屾瘡绉嶅疄浣撶敓鎴�%d-%d鏉°��
-            """.formatted(dateStart, dateEnd, min, max);
+            """.formatted(dateStart, dateEnd, dateStart, dateStart, dateStart, dateEnd, min, max);
     }
 
-    private static String buildQualityPrompt(int min, int max) {
+    private static String buildQualityPrompt(int min, int max, String dateStart) {
         return """
             璐ㄩ噺妯″潡 - 鎸変互涓嬫牸寮忕敓鎴�:
             {
               "entity": "qualityTestStandard",
-              "standardNo": "QTS-20260601-001",
+              "standardNo": "QTS-骞存湀鏃�-搴忓彿",
               "standardName": "XX浜у搧妫�楠屾爣鍑�",
               "inspectType": 0,
               "remark": "閫傜敤浜嶺X琛屼笟鐨勮川閲忔楠屾爣鍑�"
             }
             inspectType: 0=鍘熸潗鏂欐楠�, 1=杩囩▼妫�楠�, 2=鍑哄巶妫�楠屻�備笁绉嶇被鍨嬮兘瑕佽鐩栥��
+            standardNo涓殑骞存湀鏃ヤ娇鐢� %s 杩欎釜鏃ユ湡銆�
             {
               "entity": "qualityTestStandardBinding",
               "productId": 1,
               "testStandardId": 1
             }
             姣忕瀹炰綋鐢熸垚%d-%d鏉°��
-            """.formatted(min, max);
+            """.formatted(dateStart, min, max);
     }
 
     private static String buildProductionPrompt(int min, int max, String dateStart, String dateEnd) {
         return """
-            鐢熶骇妯″潡 - 鎸変互涓嬫牸寮忕敓鎴�:
+            鐢熶骇妯″潡 - 鎸変互涓嬫牸寮忕敓鎴愶紙娉ㄦ剰锛氱ず渚嬩腑鐨勬棩鏈熶粎浣滄牸寮忓弬鑰冿紝瀹為檯鏃ユ湡蹇呴』鍦� %s ~ %s 鑼冨洿鍐咃級:
             {
               "entity": "productionPlan",
               "productModelId": 1,
               "qtyRequired": 200,
-              "requiredDate": "2026-06-15",
+              "requiredDate": "%s",
               "source": "閿�鍞�",
-              "promisedDeliveryDate": "2026-07-01",
+              "promisedDeliveryDate": "%s",
               "remark": "XX瀹㈡埛璁㈠崟闇�姹�"
             }
             {
               "entity": "productionOrder",
               "productModelId": 1,
               "quantity": 200,
-              "planCompleteTime": "2026-06-30",
+              "planCompleteTime": "%s",
               "remark": "鏍规嵁鐢熶骇璁″垝XX鐢熸垚"
             }
             productionPlan鐨剆ource鍙��"閿�鍞�"鎴�"鍐呴儴"銆�
             鏃ユ湡鑼冨洿: %s ~ %s锛屾瘡绉嶅疄浣撶敓鎴�%d-%d鏉°��
-            """.formatted(dateStart, dateEnd, min, max);
+            """.formatted(dateStart, dateEnd, dateStart, dateEnd, dateEnd, dateStart, dateEnd, min, max);
     }
 
-    private static String buildStockPrompt(int min, int max) {
+    private static String buildStockPrompt(int min, int max, String dateStart) {
         return """
             搴撳瓨妯″潡 - 鎸変互涓嬫牸寮忕敓鎴�:
             {
               "entity": "stockInventory",
               "productModelId": 1,
               "qualitity": 500,
-              "batchNo": "BATCH-20260601-001",
+              "batchNo": "BATCH-骞存湀鏃�-搴忓彿",
               "warnNum": 50,
               "remark": "瀹夊叏搴撳瓨"
             }
-            姣忕瀹炰綋鐢熸垚%d-%d鏉°�俠atchNo鏍煎紡BATCH-骞存湀鏃�-搴忓彿銆�
-            """.formatted(min, max);
+            姣忕瀹炰綋鐢熸垚%d-%d鏉°�俠atchNo鏍煎紡BATCH-骞存湀鏃�-搴忓彿锛屽勾鏈堟棩浣跨敤 %s 杩欎釜鏃ユ湡銆�
+            """.formatted(min, max, dateStart);
     }
 }
diff --git a/src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java b/src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
index 34567d3..046633d 100644
--- a/src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
+++ b/src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
@@ -4,12 +4,16 @@
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.ruoyi.ai.assistant.Assistant;
+import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
+import com.ruoyi.approve.pojo.ApprovalInstance;
+import com.ruoyi.approve.service.ApprovalInstanceService;
 import com.ruoyi.basic.mapper.ProductMapper;
 import com.ruoyi.basic.mapper.ProductModelMapper;
 import com.ruoyi.basic.pojo.Customer;
 import com.ruoyi.basic.pojo.SupplierManage;
 import com.ruoyi.basic.service.ICustomerService;
 import com.ruoyi.basic.service.ISupplierService;
+import com.ruoyi.common.enums.ReviewStatusEnum;
 import com.ruoyi.mock.dto.DataGenerateRequest;
 import com.ruoyi.mock.prompt.MockDataPrompt;
 import com.ruoyi.mock.service.DataGenerateService;
@@ -20,25 +24,34 @@
 import com.ruoyi.production.service.ProductionOrderService;
 import com.ruoyi.production.service.ProductionPlanService;
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
+import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.purchase.service.IPurchaseLedgerService;
+import com.ruoyi.quality.pojo.QualityInspect;
 import com.ruoyi.quality.pojo.QualityTestStandard;
 import com.ruoyi.quality.pojo.QualityTestStandardBinding;
+import com.ruoyi.quality.service.IQualityInspectService;
 import com.ruoyi.quality.service.IQualityTestStandardService;
 import com.ruoyi.quality.service.QualityTestStandardBindingService;
 import com.ruoyi.sales.dto.SalesLedgerDto;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.service.ISalesLedgerService;
 import com.ruoyi.stock.dto.StockInventoryDto;
+import com.ruoyi.stock.service.StockInRecordService;
 import com.ruoyi.stock.service.StockInventoryService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -59,6 +72,12 @@
     private final ProductionPlanService productionPlanService;
     private final ProductionOrderService productionOrderService;
     private final StockInventoryService stockInventoryService;
+
+    // 閲囪喘瀹屾暣娴佺▼闇�瑕佺殑service
+    private final ApprovalInstanceService approvalInstanceService;
+    private final ApprovalInstanceMapper approvalInstanceMapper;
+    private final IQualityInspectService qualityInspectService;
+    private final StockInRecordService stockInRecordService;
 
     @Override
     public DataGenerateResult generate(DataGenerateRequest request) {
@@ -132,7 +151,8 @@
                 totalGenerated += s.getSuccessCount();
             }
             if (grouped.containsKey("purchaseLedger")) {
-                ModuleSummary s = createPurchaseLedgers(grouped.get("purchaseLedger"), supplierNameToId);
+                ModuleSummary s = createPurchaseLedgers(grouped.get("purchaseLedger"), supplierNameToId,
+                        request.getAdditionalInfo(), request.getDateEnd());
                 summaries.add(s);
                 totalGenerated += s.getSuccessCount();
             }
@@ -208,7 +228,23 @@
                 c.setContactPerson(item.getString("contactPerson"));
                 c.setContactPhone(item.getString("contactPhone"));
                 c.setCompanyAddress(item.getString("companyAddress"));
+                c.setCompanyPhone(item.getString("companyPhone"));
                 c.setTaxpayerIdentificationNumber(item.getString("taxpayerIdentificationNumber"));
+                c.setMaintainer(item.getString("maintainer"));
+                if (item.containsKey("maintenanceTime")) {
+                    c.setMaintenanceTime(java.sql.Date.valueOf(item.getString("maintenanceTime")));
+                } else {
+                    c.setMaintenanceTime(new java.sql.Date(System.currentTimeMillis()));
+                }
+                if (item.containsKey("bankAccount")) {
+                    c.setBankAccount(item.getString("bankAccount"));
+                }
+                if (item.containsKey("basicBankAccount")) {
+                    c.setBasicBankAccount(item.getString("basicBankAccount"));
+                }
+                if (item.containsKey("bankCode")) {
+                    c.setBankCode(item.getString("bankCode"));
+                }
                 customerService.insertCustomer(c);
                 if (c.getId() != null) {
                     nameToId.put(c.getCustomerName(), c.getId());
@@ -232,6 +268,7 @@
                 s.setContactUserName(item.getString("contactUserName"));
                 s.setContactUserPhone(item.getString("contactUserPhone"));
                 s.setCompanyAddress(item.getString("companyAddress"));
+                s.setCompanyPhone(item.getString("companyPhone"));
                 s.setTaxpayerIdentificationNum(item.getString("taxpayerIdentificationNum"));
                 s.setBankAccountName(item.getString("bankAccountName"));
                 s.setBankAccountNum(item.getString("bankAccountNum"));
@@ -286,6 +323,10 @@
                 dto.setSalesman(item.getString("salesman"));
                 dto.setPaymentMethod(item.getString("paymentMethod"));
                 dto.setType(item.getInteger("type"));
+                // 褰曞叆浜猴細浼樺厛浣跨敤AI鎻愪緵鐨勬暟鎹紝鍚﹀垯鐢ㄥ綋鍓嶇櫥褰曠敤鎴�
+                if (item.containsKey("entryPerson")) {
+                    dto.setEntryPerson(item.getString("entryPerson"));
+                }
                 if (item.containsKey("entryDate")) {
                     dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate")));
                 }
@@ -309,6 +350,17 @@
                         slp.setTaxRate(pd.getBigDecimal("taxRate"));
                         slp.setUnit(pd.getString("unit"));
                         slp.setType(pd.getInteger("type"));
+                        if (pd.containsKey("taxExclusiveTotalPrice")) {
+                            slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice"));
+                        } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) {
+                            // 涓嶅惈绋庢�讳环 = 鍚◣鎬讳环 / (1 + 绋庣巼/100)
+                            slp.setTaxExclusiveTotalPrice(
+                                pd.getBigDecimal("taxInclusiveTotalPrice").divide(
+                                    BigDecimal.ONE.add(pd.getBigDecimal("taxRate").divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP)),
+                                    2, RoundingMode.HALF_UP));
+                        } else {
+                            slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO);
+                        }
                         products.add(slp);
                     }
                     dto.setProductData(products);
@@ -323,7 +375,11 @@
         return summary("sales", "閿�鍞彴璐�", items.size(), success, fail);
     }
 
-    private ModuleSummary createPurchaseLedgers(List<JSONObject> items, Map<String, Long> supplierNameToId) {
+    private ModuleSummary createPurchaseLedgers(List<JSONObject> items, Map<String, Long> supplierNameToId,
+                                                 String additionalInfo, String dateEnd) {
+        // 鏄惁闇�瑕佽川妫�锛屼粠琛ュ厖淇℃伅鍒ゆ柇锛岄粯璁や笉闇�瑕�
+        boolean needQualityInspect = additionalInfo != null
+                && (additionalInfo.contains("璐ㄦ") || additionalInfo.contains("闇�瑕佹楠�"));
         int success = 0, fail = 0;
         for (JSONObject item : items) {
             try {
@@ -337,8 +393,12 @@
                 dto.setProjectName(item.getString("projectName"));
                 dto.setContractAmount(item.getBigDecimal("contractAmount"));
                 dto.setPaymentMethod(item.getString("paymentMethod"));
+
+                String entryDateStr = item.getString("entryDate");
+                LocalDate entryDate = null;
                 if (item.containsKey("entryDate")) {
-                    dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate")));
+                    entryDate = LocalDate.parse(entryDateStr);
+                    dto.setEntryDate(java.sql.Date.valueOf(entryDateStr));
                 }
                 if (item.containsKey("executionDate")) {
                     dto.setExecutionDate(java.sql.Date.valueOf(item.getString("executionDate")));
@@ -357,11 +417,32 @@
                         slp.setTaxRate(pd.getBigDecimal("taxRate"));
                         slp.setUnit(pd.getString("unit"));
                         slp.setType(2);
+                        // 鏄惁璐ㄦ锛氫粠琛ュ厖淇℃伅鍒ゆ柇锛岄粯璁や笉闇�瑕�
+                        slp.setIsChecked(needQualityInspect);
+                        if (pd.containsKey("taxExclusiveTotalPrice")) {
+                            slp.setTaxExclusiveTotalPrice(pd.getBigDecimal("taxExclusiveTotalPrice"));
+                        } else if (pd.getBigDecimal("taxInclusiveTotalPrice") != null && pd.getBigDecimal("taxRate") != null) {
+                            slp.setTaxExclusiveTotalPrice(
+                                pd.getBigDecimal("taxInclusiveTotalPrice").divide(
+                                    BigDecimal.ONE.add(pd.getBigDecimal("taxRate").divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP)),
+                                    2, RoundingMode.HALF_UP));
+                        } else {
+                            slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO);
+                        }
                         products.add(slp);
                     }
                     dto.setProductData(products);
                 }
                 purchaseLedgerService.addOrEditPurchase(dto);
+                // 閫氳繃鍚堝悓鍙锋壘鍒板垰鍒涘缓鐨勯噰璐彴璐�
+                PurchaseLedger savedLedger = purchaseLedgerService.getOne(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<PurchaseLedger>()
+                                .eq(PurchaseLedger::getPurchaseContractNumber, dto.getPurchaseContractNumber())
+                                .last("limit 1"));
+                if (savedLedger != null) {
+                    // 璧板畬鏁存祦绋嬶細瀹℃牳閫氳繃 鈫� 璐ㄦ(鍙��) 鈫� 鍏ュ簱 + 鍏ュ簱瀹℃牳閫氳繃
+                    processPurchaseFullFlow(savedLedger, needQualityInspect, entryDate, dateEnd);
+                }
                 success++;
             } catch (Exception e) {
                 log.warn("鍒涘缓閲囪喘鍙拌处澶辫触: {}", e.getMessage());
@@ -371,6 +452,108 @@
         return summary("purchase", "閲囪喘鍙拌处", items.size(), success, fail);
     }
 
+    /**
+     * 閲囪喘瀹屾暣娴佺▼: 瀹℃牳閫氳繃 鈫� 璐ㄦ(鍙��) 鈫� 鍏ュ簱瀹℃牳閫氳繃
+     */
+    private void processPurchaseFullFlow(PurchaseLedger purchaseLedger, boolean needQualityInspect,
+                                          LocalDate entryDate, String dateEnd) {
+        try {
+            // 1. 瀹℃壒鑷姩閫氳繃
+            ApprovalInstance approvalInstance = approvalInstanceMapper.selectOne(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstance>()
+                            .eq(ApprovalInstance::getBusinessId, purchaseLedger.getId())
+                            .eq(ApprovalInstance::getBusinessType, 5L)
+                            .eq(ApprovalInstance::getDeleted, 0)
+                            .orderByDesc(ApprovalInstance::getId)
+                            .last("limit 1"));
+            if (approvalInstance != null) {
+                // 缁撶畻瀹℃壒寮�濮嬫椂闂达細鍩轰簬褰曞叆鏃ユ湡锛岄殢鏈烘帹0-3澶�
+                LocalDate baseDate = entryDate != null ? entryDate : LocalDate.now();
+                LocalDate approveDate = baseDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
+                // 浣跨敤autoApprove瀹屾垚瀹℃壒
+                approvalInstanceService.autoApprove(approvalInstance.getId());
+                log.info("閲囪喘鍙拌处[{}]瀹℃壒閫氳繃, 瀹℃壒鏃ユ湡: {}", purchaseLedger.getPurchaseContractNumber(), approveDate);
+            }
+
+            // 2. 璐ㄦ娴佺▼锛堝鏋滈渶瑕佽川妫�锛�
+            if (needQualityInspect) {
+                processQualityInspect(purchaseLedger, entryDate, dateEnd);
+            }
+
+            // 3. 鍏ュ簱瀹℃壒閫氳繃
+            processStockInApprove(purchaseLedger, dateEnd);
+
+        } catch (Exception e) {
+            log.warn("閲囪喘瀹屾暣娴佺▼澶勭悊澶辫触[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
+        }
+    }
+
+    /**
+     * 璐ㄦ: 鎵惧埌閲囪喘鍏宠仈鐨勮川妫�鍗曪紝鑷姩鎻愪氦涓哄悎鏍�
+     */
+    private void processQualityInspect(PurchaseLedger purchaseLedger, LocalDate entryDate, String dateEnd) {
+        try {
+            List<QualityInspect> inspectList = qualityInspectService.list(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>()
+                            .eq(QualityInspect::getPurchaseLedgerId, purchaseLedger.getId()));
+            for (QualityInspect qi : inspectList) {
+                if (qi.getInspectState() == null || qi.getInspectState() == 0) {
+                    qualityInspectService.autoSubmit(qi.getId());
+                    log.info("閲囪喘鍙拌处[{}]璐ㄦ鍗昜{}]鑷姩鎻愪氦鍚堟牸", purchaseLedger.getPurchaseContractNumber(), qi.getId());
+                }
+            }
+        } catch (Exception e) {
+            log.warn("璐ㄦ娴佺▼澶勭悊澶辫触[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
+        }
+    }
+
+    /**
+     * 鍏ュ簱瀹℃牳: 鎵惧埌鍏ュ簱璁板綍骞跺鎵归�氳繃
+     */
+    private void processStockInApprove(PurchaseLedger purchaseLedger, String dateEnd) {
+        try {
+            List<com.ruoyi.stock.pojo.StockInRecord> stockRecords = stockInRecordService.list(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
+                            .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, purchaseLedger.getId())
+                            .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordType,
+                                    String.valueOf(com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode())));
+            // 濡傛灉鎸塒URCHASE_STOCK_IN鎵句笉鍒帮紝灏濊瘯CUSTOMIZATION_UNSTOCK_OUT(璐ㄦ鍚堟牸鍏ュ簱)
+            if (stockRecords.isEmpty()) {
+                stockRecords = stockInRecordService.list(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
+                                .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, purchaseLedger.getId())
+                                .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordType,
+                                        String.valueOf(com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_OUT.getCode())));
+            }
+            // 涔熷皾璇曟寜璐ㄦ鍗旾D鏌ユ壘(璐ㄦ鍗曠殑recordId鏄川妫�鍗旾D)
+            for (QualityInspect qi : qualityInspectService.list(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>()
+                            .eq(QualityInspect::getPurchaseLedgerId, purchaseLedger.getId()))) {
+                List<com.ruoyi.stock.pojo.StockInRecord> qiRecords = stockInRecordService.list(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
+                                .eq(com.ruoyi.stock.pojo.StockInRecord::getRecordId, qi.getId()));
+                stockRecords.addAll(qiRecords);
+            }
+            // 鍘婚噸
+            stockRecords = stockRecords.stream()
+                    .collect(Collectors.toMap(com.ruoyi.stock.pojo.StockInRecord::getId, r -> r, (a, b) -> a))
+                    .values().stream().collect(Collectors.toList());
+
+            if (!stockRecords.isEmpty()) {
+                List<Long> recordIds = stockRecords.stream()
+                        .filter(r -> r.getApprovalStatus() == null || r.getApprovalStatus() == 0)
+                        .map(com.ruoyi.stock.pojo.StockInRecord::getId)
+                        .collect(Collectors.toList());
+                if (!recordIds.isEmpty()) {
+                    stockInRecordService.batchApprove(recordIds, ReviewStatusEnum.APPROVED.getCode());
+                    log.info("閲囪喘鍙拌处[{}]鍏ュ簱瀹℃壒閫氳繃, 鍏ュ簱璁板綍鏁�: {}", purchaseLedger.getPurchaseContractNumber(), recordIds.size());
+                }
+            }
+        } catch (Exception e) {
+            log.warn("鍏ュ簱瀹℃壒澶辫触[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
+        }
+    }
+
     private ModuleSummary createProductionPlans(List<JSONObject> items) {
         int success = 0, fail = 0;
         for (JSONObject item : items) {
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 7b71ef3..b3a7727 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -571,6 +571,10 @@
         SalesLedger salesLedger = convertToEntity(salesLedgerDto);
         salesLedger.setCustomerName(customer.getCustomerName());
         salesLedger.setTenantId(customer.getTenantId());
+        // 褰曞叆浜猴細濡傛灉鏈紶鍒欎娇鐢ㄥ綋鍓嶇櫥褰曠敤鎴�
+        if (StringUtils.isEmpty(salesLedger.getEntryPerson())) {
+            salesLedger.setEntryPerson(String.valueOf(SecurityUtils.getUserId()));
+        }
         // 3. 鏂板鎴栨洿鏂颁富琛�
         if (salesLedger.getId() == null) {
             String contractNo = salesLedger.getSalesContractNo();

--
Gitblit v1.9.3