From d5bbd17a1428811da046ec3be3c0cc943a7ae059 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 17 六月 2026 15:13:20 +0800
Subject: [PATCH] ai数据自动生成

---
 src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java | 1205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 1,150 insertions(+), 55 deletions(-)

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 046633d..92b7cb8 100644
--- a/src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
+++ b/src/main/java/com/ruoyi/mock/service/impl/DataGenerateServiceImpl.java
@@ -5,27 +5,51 @@
 import com.alibaba.fastjson2.JSONObject;
 import com.ruoyi.ai.assistant.Assistant;
 import com.ruoyi.approve.mapper.ApprovalInstanceMapper;
+import com.ruoyi.approve.mapper.ApprovalInstanceNodeMapper;
+import com.ruoyi.approve.mapper.ApprovalRecordMapper;
+import com.ruoyi.approve.mapper.ApprovalTaskMapper;
 import com.ruoyi.approve.pojo.ApprovalInstance;
+import com.ruoyi.approve.pojo.ApprovalInstanceNode;
+import com.ruoyi.approve.pojo.ApprovalRecord;
+import com.ruoyi.approve.pojo.ApprovalTask;
 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.Product;
+import com.ruoyi.basic.pojo.ProductModel;
 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.common.enums.StockInQualifiedRecordTypeEnum;
+import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
+import com.ruoyi.common.utils.OrderUtils;
 import com.ruoyi.mock.dto.DataGenerateRequest;
 import com.ruoyi.mock.prompt.MockDataPrompt;
 import com.ruoyi.mock.service.DataGenerateService;
 import com.ruoyi.mock.vo.DataGenerateResult;
 import com.ruoyi.mock.vo.DataGenerateResult.ModuleSummary;
-import com.ruoyi.production.pojo.ProductionOrder;
-import com.ruoyi.production.pojo.ProductionPlan;
+import com.ruoyi.procurementrecord.utils.StockUtils;
+import com.ruoyi.production.bean.dto.ProductionOrderPickDto;
+import com.ruoyi.production.bean.dto.ProductionPlanDto;
+import com.ruoyi.production.bean.dto.ProductionProductMainDto;
+import com.ruoyi.production.bean.vo.ProductionBomStructureVo;
+import com.ruoyi.production.mapper.*;
+import com.ruoyi.production.pojo.*;
+import com.ruoyi.production.service.ProductionOrderPickService;
 import com.ruoyi.production.service.ProductionOrderService;
 import com.ruoyi.production.service.ProductionPlanService;
+import com.ruoyi.production.service.ProductionProductMainService;
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.purchase.service.IPurchaseLedgerService;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.mapper.SysDeptMapper;
+import com.ruoyi.project.system.mapper.SysUserDeptMapper;
+import com.ruoyi.project.system.mapper.SysUserMapper;
+import com.ruoyi.quality.mapper.QualityInspectMapper;
 import com.ruoyi.quality.pojo.QualityInspect;
 import com.ruoyi.quality.pojo.QualityTestStandard;
 import com.ruoyi.quality.pojo.QualityTestStandardBinding;
@@ -33,11 +57,29 @@
 import com.ruoyi.quality.service.IQualityTestStandardService;
 import com.ruoyi.quality.service.QualityTestStandardBindingService;
 import com.ruoyi.sales.dto.SalesLedgerDto;
+import com.ruoyi.sales.dto.ShippingInfoDto;
+import com.ruoyi.sales.mapper.SalesLedgerMapper;
+import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
+import com.ruoyi.sales.mapper.ShippingInfoMapper;
+import com.ruoyi.sales.mapper.ShippingProductDetailMapper;
+import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
+import com.ruoyi.sales.pojo.ShippingInfo;
+import com.ruoyi.sales.pojo.ShippingProductDetail;
 import com.ruoyi.sales.service.ISalesLedgerService;
+import com.ruoyi.sales.service.ShippingInfoService;
+import com.ruoyi.stock.mapper.StockInRecordMapper;
+import com.ruoyi.stock.mapper.StockInventoryMapper;
+import com.ruoyi.stock.mapper.StockOutRecordMapper;
+import com.ruoyi.stock.pojo.StockInventory;
+import com.ruoyi.stock.pojo.StockOutRecord;
 import com.ruoyi.stock.dto.StockInventoryDto;
 import com.ruoyi.stock.service.StockInRecordService;
+import com.ruoyi.stock.service.StockOutRecordService;
 import com.ruoyi.stock.service.StockInventoryService;
+import com.ruoyi.technology.mapper.TechnologyBomStructureMapper;
+import com.ruoyi.technology.mapper.TechnologyRoutingMapper;
+import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -46,11 +88,15 @@
 import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.stream.Collectors;
 
@@ -76,8 +122,43 @@
     // 閲囪喘瀹屾暣娴佺▼闇�瑕佺殑service
     private final ApprovalInstanceService approvalInstanceService;
     private final ApprovalInstanceMapper approvalInstanceMapper;
+    private final ApprovalInstanceNodeMapper approvalInstanceNodeMapper;
+    private final ApprovalTaskMapper approvalTaskMapper;
+    private final ApprovalRecordMapper approvalRecordMapper;
     private final IQualityInspectService qualityInspectService;
+    private final QualityInspectMapper qualityInspectMapper;
     private final StockInRecordService stockInRecordService;
+    private final StockInRecordMapper stockInRecordMapper;
+
+    // 閿�鍞畬鏁存祦绋嬮渶瑕佺殑service/mapper
+    private final SalesLedgerMapper salesLedgerMapper;
+    private final SalesLedgerProductMapper salesLedgerProductMapper;
+    private final ProductionPlanMapper productionPlanMapper;
+    private final ProductionOrderMapper productionOrderMapper;
+    private final ProductionOperationTaskMapper productionOperationTaskMapper;
+    private final ProductionProductMainService productionProductMainService;
+    private final ShippingInfoService shippingInfoService;
+    private final ShippingInfoMapper shippingInfoMapper;
+    private final ShippingProductDetailMapper shippingProductDetailMapper;
+    private final StockUtils stockUtils;
+    private final StockOutRecordMapper stockOutRecordMapper;
+    private final StockOutRecordService stockOutRecordService;
+    private final StockInventoryMapper stockInventoryMapper;
+
+    // 宸ヨ壓鏁版嵁妫�娴�
+    private final TechnologyRoutingMapper technologyRoutingMapper;
+    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
+    private final TechnologyBomStructureMapper technologyBomStructureMapper;
+
+    // 棰嗘枡
+    private final ProductionOrderPickService productionOrderPickService;
+    private final ProductionOrderBomMapper productionOrderBomMapper;
+    private final ProductionBomStructureMapper productionBomStructureMapper;
+
+    // 鐢ㄦ埛/瑙掕壊鏌ヨ
+    private final SysUserMapper sysUserMapper;
+    private final SysDeptMapper sysDeptMapper;
+    private final SysUserDeptMapper sysUserDeptMapper;
 
     @Override
     public DataGenerateResult generate(DataGenerateRequest request) {
@@ -87,10 +168,18 @@
         int totalGenerated = 0;
 
         try {
-            List<Long> productIds = productMapper.selectList(null).stream()
-                    .map(p -> p.getId()).collect(Collectors.toList());
-            List<Long> productModelIds = productModelMapper.selectList(null).stream()
-                    .map(m -> m.getId()).collect(Collectors.toList());
+            // 鏋勫缓浜у搧瑙勬牸鍒嗙被锛氶�氳繃Product鏍戞牴鑺傜偣鍒ゆ柇鎴愬搧/鍘熸潗鏂�
+            Map<Long, String> productModelIdToCategory = buildProductModelCategoryMap();
+            List<Long> productModelIds = new ArrayList<>(productModelIdToCategory.keySet());
+
+            // 鍔犺浇宸叉湁瀹㈡埛/渚涘簲鍟嗭紙涓嶆柊澧烇紝浣跨敤宸叉湁鏁版嵁锛�
+            Map<String, Long> customerNameToId = loadExistingCustomers();
+            Map<String, Long> supplierNameToId = loadExistingSuppliers();
+            List<String> existingCustomerNames = new ArrayList<>(customerNameToId.keySet());
+            List<String> existingSupplierNames = new ArrayList<>(supplierNameToId.keySet());
+
+            // 鍔犺浇绯荤粺鐢ㄦ埛淇℃伅锛堟樀绉般�佽鑹层�侀儴闂級
+            List<SysUser> systemUsers = loadSystemUsersWithDetail();
 
             String systemPrompt = MockDataPrompt.buildSystemPrompt();
             String userMessage = MockDataPrompt.buildUserMessage(
@@ -98,7 +187,9 @@
                     request.getCountMin(), request.getCountMax(),
                     request.getDateStart(), request.getDateEnd(),
                     request.getAdditionalInfo(),
-                    productIds, productModelIds);
+                    productModelIdToCategory,
+                    systemUsers,
+                    existingCustomerNames, existingSupplierNames);
 
             String fullPrompt = systemPrompt + "\n\n" + userMessage;
             log.info("璋冪敤AI鐢熸垚妯℃嫙鏁版嵁, modules={}, industries={}", request.getModules(), request.getIndustries());
@@ -120,24 +211,17 @@
                 return result;
             }
 
+            // 淇AI鐢熸垚鐨勬棩鏈熷埌鎸囧畾鏃堕棿鑼冨洿鍐�
+            String dateStart = request.getDateStart();
+            String dateEnd = request.getDateEnd();
+            if (dateStart != null && dateEnd != null) {
+                fixDatesInRange(entities, dateStart, dateEnd);
+            }
+
             Map<String, List<JSONObject>> grouped = entities.stream()
                     .collect(Collectors.groupingBy(e -> e.getString("entity")));
 
-            // 鍚嶇О鈫扞D 鏄犲皠琛紝鐢ㄤ簬鍒涘缓涓氬姟鍗曟嵁鏃跺洖濉閿�
-            Map<String, Long> customerNameToId = new HashMap<>();
-            Map<String, Long> supplierNameToId = new HashMap<>();
-
-            // Tier 0: 鍩虹鏁版嵁
-            if (grouped.containsKey("customer")) {
-                ModuleSummary s = createCustomers(grouped.get("customer"), customerNameToId);
-                summaries.add(s);
-                totalGenerated += s.getSuccessCount();
-            }
-            if (grouped.containsKey("supplier")) {
-                ModuleSummary s = createSuppliers(grouped.get("supplier"), supplierNameToId);
-                summaries.add(s);
-                totalGenerated += s.getSuccessCount();
-            }
+            // Tier 0: 鍩虹鏁版嵁锛堝鎴峰拰渚涘簲鍟嗕笉鑷姩鐢熸垚锛屼娇鐢ㄥ凡鏈夋暟鎹級
             if (grouped.containsKey("qualityTestStandard")) {
                 ModuleSummary s = createQualityStandards(grouped.get("qualityTestStandard"));
                 summaries.add(s);
@@ -146,13 +230,13 @@
 
             // Tier 1: 涓氬姟鍗曟嵁
             if (grouped.containsKey("salesLedger")) {
-                ModuleSummary s = createSalesLedgers(grouped.get("salesLedger"), customerNameToId);
+                ModuleSummary s = createSalesLedgers(grouped.get("salesLedger"), customerNameToId, request.getDateStart());
                 summaries.add(s);
                 totalGenerated += s.getSuccessCount();
             }
             if (grouped.containsKey("purchaseLedger")) {
                 ModuleSummary s = createPurchaseLedgers(grouped.get("purchaseLedger"), supplierNameToId,
-                        request.getAdditionalInfo(), request.getDateEnd());
+                        request.getAdditionalInfo(), request.getDateStart(), request.getDateEnd());
                 summaries.add(s);
                 totalGenerated += s.getSuccessCount();
             }
@@ -216,7 +300,154 @@
         }
     }
 
+    /**
+     * 淇AI鐢熸垚鐨勬棩鏈熷埌鎸囧畾鏃堕棿鑼冨洿鍐呫��
+     * 閬嶅巻鎵�鏈夊疄浣撶殑鎵�鏈夊瓧娈碉紝濡傛灉鍙戠幇鏃ユ湡瀛楃涓诧紙yyyy-MM-dd鏍煎紡锛夎秴鍑鸿寖鍥达紝鏇挎崲涓鸿寖鍥村唴鐨勯殢鏈烘棩鏈熴��
+     */
+    private void fixDatesInRange(List<JSONObject> entities, String dateStart, String dateEnd) {
+        LocalDate start;
+        LocalDate end;
+        try {
+            start = LocalDate.parse(dateStart);
+            end = LocalDate.parse(dateEnd);
+        } catch (Exception e) {
+            log.warn("鏃ユ湡鑼冨洿瑙f瀽澶辫触: {} ~ {}", dateStart, dateEnd);
+            return;
+        }
+        long daysBetween = ChronoUnit.DAYS.between(start, end);
+        if (daysBetween <= 0) {
+            daysBetween = 1;
+        }
+
+        // 鎵�鏈夊凡鐭ョ殑鏃ユ湡瀛楁鍚�
+        java.util.Set<String> dateFields = java.util.Set.of(
+                "entryDate", "executionDate", "deliveryDate", "requiredDate",
+                "promisedDeliveryDate", "planCompleteTime", "maintenanceTime",
+                "checkTime", "registerDate"
+        );
+
+        for (JSONObject entity : entities) {
+            for (String key : dateFields) {
+                String val = entity.getString(key);
+                if (val != null && val.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                    try {
+                        LocalDate d = LocalDate.parse(val);
+                        if (d.isBefore(start) || d.isAfter(end)) {
+                            LocalDate fixed = start.plusDays(ThreadLocalRandom.current().nextLong(daysBetween + 1));
+                            entity.put(key, fixed.toString());
+                            log.debug("淇鏃ユ湡 {}: {} -> {}", key, val, fixed);
+                        }
+                    } catch (Exception ignored) {
+                    }
+                } else if (val != null && !val.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                    // AI杩斿洖浜嗘棤鏁堟棩鏈熸牸寮忥紝鐩存帴鏇挎崲涓鸿寖鍥村唴鐨勯殢鏈烘棩鏈�
+                    LocalDate fixed = start.plusDays(ThreadLocalRandom.current().nextLong(daysBetween + 1));
+                    entity.put(key, fixed.toString());
+                    log.debug("淇鏃犳晥鏃ユ湡 {}: {} -> {}", key, val, fixed);
+                }
+            }
+            // 淇鍚堝悓缂栧彿涓殑鏃ユ湡: CG-20230601-001 -> CG-YYYYMMDD-001
+            for (String key : java.util.Set.of("purchaseContractNumber", "salesContractNo", "standardNo", "batchNo")) {
+                String val = entity.getString(key);
+                if (val != null && val.matches(".*\\d{8}.*")) {
+                    String datePart = val.replaceAll(".*?(\\d{8}).*", "$1");
+                    try {
+                        // 楠岃瘉鎻愬彇鍒扮殑鏄湁鏁堟棩鏈�
+                        String dateStr = datePart.substring(0, 4) + "-" + datePart.substring(4, 6) + "-" + datePart.substring(6, 8);
+                        LocalDate d = LocalDate.parse(dateStr);
+                        if (d.isBefore(start) || d.isAfter(end)) {
+                            LocalDate fixed = start.plusDays(ThreadLocalRandom.current().nextLong(daysBetween + 1));
+                            String newDatePart = fixed.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
+                            String newVal = val.replace(datePart, newDatePart);
+                            entity.put(key, newVal);
+                            log.debug("淇缂栧彿 {}: {} -> {}", key, val, newVal);
+                        }
+                    } catch (Exception ignored) {
+                    }
+                }
+            }
+        }
+    }
+
     // ---- Tier 0: 鍩虹鏁版嵁 ----
+
+    /**
+     * 浠庢暟鎹簱鍔犺浇宸叉湁瀹㈡埛鍚嶇О鈫扞D鏄犲皠
+     */
+    private Map<String, Long> loadExistingCustomers() {
+        Map<String, Long> map = new HashMap<>();
+        List<Customer> customers = customerService.list();
+        for (Customer c : customers) {
+            if (c.getCustomerName() != null) {
+                map.put(c.getCustomerName(), c.getId());
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 浠庢暟鎹簱鍔犺浇宸叉湁渚涘簲鍟嗗悕绉扳啋ID鏄犲皠
+     */
+    private Map<String, Long> loadExistingSuppliers() {
+        Map<String, Long> map = new HashMap<>();
+        List<SupplierManage> suppliers = supplierService.list();
+        for (SupplierManage s : suppliers) {
+            if (s.getSupplierName() != null) {
+                map.put(s.getSupplierName(), s.getId());
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 鍔犺浇绯荤粺鐢ㄦ埛淇℃伅锛堝惈瑙掕壊鍜岄儴闂ㄥ悕绉帮級
+     */
+    private List<SysUser> loadSystemUsersWithDetail() {
+        return sysUserMapper.selectUserListWithDetail();
+    }
+
+    /**
+     * 鏋勫缓浜у搧瑙勬牸ID鈫掗《绾т骇鍝佸垎绫诲悕绉扮殑鏄犲皠
+     * 閫氳繃Product鏍戝悜涓婃壘鍒版牴鑺傜偣锛屽垽鏂�"鎴愬搧"/"鍘熸潗鏂�"/"鍗婃垚鍝�"
+     */
+    private Map<Long, String> buildProductModelCategoryMap() {
+        // 鍔犺浇鎵�鏈塒roduct鑺傜偣
+        List<Product> allProducts = productMapper.selectList(null);
+        Map<Long, Product> productMap = allProducts.stream()
+                .collect(Collectors.toMap(Product::getId, p -> p, (a, b) -> a));
+
+        // 瀵规瘡涓狿roduct锛屾部parentId鍚戜笂鎵惧埌鏍硅妭鐐瑰悕绉�
+        Map<Long, String> productIdToRootName = new HashMap<>();
+        for (Product p : allProducts) {
+            if (productIdToRootName.containsKey(p.getId())) continue;
+            // 鍚戜笂閬嶅巻鎵炬牴
+            List<Long> chain = new ArrayList<>();
+            Long currentId = p.getId();
+            while (currentId != null) {
+                chain.add(currentId);
+                Product current = productMap.get(currentId);
+                if (current == null || current.getParentId() == null) break;
+                currentId = current.getParentId();
+            }
+            // 鏍硅妭鐐圭殑productName灏辨槸鍒嗙被鍚�
+            Product root = productMap.get(chain.get(chain.size() - 1));
+            String rootName = root != null ? root.getProductName() : "鍏朵粬";
+            for (Long id : chain) {
+                productIdToRootName.put(id, rootName);
+            }
+        }
+
+        // 瀵规瘡涓狿roductModel锛岄�氳繃productId鎵惧埌鍏舵墍灞炲垎绫�
+        List<ProductModel> allModels = productModelMapper.selectList(null);
+        Map<Long, String> result = new HashMap<>();
+        for (ProductModel m : allModels) {
+            String category = m.getProductId() != null
+                    ? productIdToRootName.getOrDefault(m.getProductId(), "鍏朵粬")
+                    : "鍏朵粬";
+            result.put(m.getId(), category);
+        }
+        return result;
+    }
 
     private ModuleSummary createCustomers(List<JSONObject> items, Map<String, Long> nameToId) {
         int success = 0, fail = 0;
@@ -232,7 +463,10 @@
                 c.setTaxpayerIdentificationNumber(item.getString("taxpayerIdentificationNumber"));
                 c.setMaintainer(item.getString("maintainer"));
                 if (item.containsKey("maintenanceTime")) {
-                    c.setMaintenanceTime(java.sql.Date.valueOf(item.getString("maintenanceTime")));
+                    String mtStr = item.getString("maintenanceTime");
+                    if (mtStr != null && mtStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                        c.setMaintenanceTime(java.sql.Date.valueOf(mtStr));
+                    }
                 } else {
                     c.setMaintenanceTime(new java.sql.Date(System.currentTimeMillis()));
                 }
@@ -309,7 +543,7 @@
 
     // ---- Tier 1: 涓氬姟鍗曟嵁 ----
 
-    private ModuleSummary createSalesLedgers(List<JSONObject> items, Map<String, Long> customerNameToId) {
+    private ModuleSummary createSalesLedgers(List<JSONObject> items, Map<String, Long> customerNameToId, String dateStart) {
         int success = 0, fail = 0;
         for (JSONObject item : items) {
             try {
@@ -323,20 +557,56 @@
                 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"));
+
+                // 褰曞叆浜猴細浼樺厛鐢ˋI杩斿洖鐨勶紝鍚﹀垯浠�"閿�鍞�"瑙掕壊/閮ㄩ棬闅忔満閫�
+                String entryPerson = item.getString("entryPerson");
+                if (entryPerson == null || entryPerson.isBlank()) {
+                    SysUser salesUser = randomUserByKeyword("閿�鍞�");
+                    entryPerson = salesUser != null ? salesUser.getNickName() : "绯荤粺";
                 }
+                dto.setEntryPerson(entryPerson);
+
+                // 涓氬姟鍛橈細浼樺厛鐢ˋI杩斿洖鐨勶紝鍚﹀垯浠�"閿�鍞�"瑙掕壊/閮ㄩ棬闅忔満閫�
+                String salesman = dto.getSalesman();
+                if (salesman == null || salesman.isBlank()) {
+                    SysUser salesUser = randomUserByKeyword("閿�鍞�");
+                    salesman = salesUser != null ? salesUser.getNickName() : "绯荤粺";
+                    dto.setSalesman(salesman);
+                }
+                // customerId涓簄ull浼氬鑷�"瀹㈡埛涓嶅瓨鍦�"寮傚父锛岃烦杩�
+                if (customerId == null) {
+                    log.warn("璺宠繃閿�鍞彴璐︼紝瀹㈡埛[{}]涓嶅瓨鍦�", customerName);
+                    fail++;
+                    continue;
+                }
+                LocalDate entryDate = null;
                 if (item.containsKey("entryDate")) {
-                    dto.setEntryDate(java.sql.Date.valueOf(item.getString("entryDate")));
+                    String entryDateStr = item.getString("entryDate");
+                    if (entryDateStr != null && entryDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                        entryDate = LocalDate.parse(entryDateStr);
+                        dto.setEntryDate(java.sql.Date.valueOf(entryDateStr));
+                    } else {
+                        dto.setEntryDate(java.sql.Date.valueOf(dateStart));
+                    }
                 }
                 if (item.containsKey("executionDate")) {
-                    dto.setExecutionDate(LocalDate.parse(item.getString("executionDate")));
+                    String execDateStr = item.getString("executionDate");
+                    if (execDateStr != null && execDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                        dto.setExecutionDate(LocalDate.parse(execDateStr));
+                    } else {
+                        dto.setExecutionDate(LocalDate.parse(dateStart));
+                    }
                 }
                 if (item.containsKey("deliveryDate")) {
-                    dto.setDeliveryDate(LocalDate.parse(item.getString("deliveryDate")));
+                    String delDateStr = item.getString("deliveryDate");
+                    if (delDateStr != null && delDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                        dto.setDeliveryDate(LocalDate.parse(delDateStr));
+                    } else {
+                        dto.setDeliveryDate(LocalDate.parse(dateStart));
+                    }
                 }
                 JSONArray productData = item.getJSONArray("productData");
+                boolean hasProduction = false;
                 if (productData != null) {
                     List<SalesLedgerProduct> products = new ArrayList<>();
                     for (int i = 0; i < productData.size(); i++) {
@@ -353,7 +623,6 @@
                         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)),
@@ -361,22 +630,603 @@
                         } else {
                             slp.setTaxExclusiveTotalPrice(BigDecimal.ZERO);
                         }
+                        slp.setIsProduction(true);
                         products.add(slp);
+                        hasProduction = true;
                     }
                     dto.setProductData(products);
                 }
                 salesLedgerService.addOrUpdateSalesLedger(dto);
+                // addOrUpdateSalesLedger鍐呴儴浼氳嚜鍔ㄧ敓鎴愬悎鍚屽彿骞秈nsert锛屼絾dto涓婃病鏈夊洖鍐�
+                // 鐩存帴鐢╠to鐨別ntryDate鍜宑ustomerId鏌ユ渶鏂板垱寤虹殑璁板綍
+                SalesLedger savedLedger = salesLedgerMapper.selectOne(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedger>()
+                                .eq(SalesLedger::getCustomerId, dto.getCustomerId())
+                                .orderByDesc(SalesLedger::getId)
+                                .last("limit 1"));
+                if (savedLedger != null && hasProduction) {
+                    processSalesFullFlow(savedLedger, entryDate);
+                }
                 success++;
             } catch (Exception e) {
-                log.warn("鍒涘缓閿�鍞彴璐﹀け璐�: {}", e.getMessage());
+                log.warn("鍒涘缓閿�鍞彴璐﹀け璐�: {}", e.getMessage(), e);
                 fail++;
             }
         }
         return summary("sales", "閿�鍞彴璐�", items.size(), success, fail);
     }
 
+    // ==================== 閿�鍞畬鏁存祦绋� ====================
+
+    /**
+     * 閿�鍞畬鏁存祦绋�: 鐢熶骇璁″垝鍚堝苟涓嬪彂 鈫� 棰嗘枡 鈫� 鎶ュ伐 鈫� 璐ㄦ(鍙��) 鈫� 鍏ュ簱 鈫� 鍙戣揣 鈫� 鍑哄簱
+     * 鏃堕棿浠ラ攢鍞綍鍏ユ棩鏈熶负鍩哄噯锛屽悇鐜妭閫掓帹0-3澶�
+     */
+    private void processSalesFullFlow(SalesLedger salesLedger, LocalDate entryDate) {
+        try {
+            LocalDate baseDate = entryDate != null ? entryDate : LocalDate.now();
+
+            // 1. 鏌ヨ閿�鍞彴璐︿骇鍝侊紙鍚敓浜ц鍒掞級
+            List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedgerProduct>()
+                            .eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId())
+                            .eq(SalesLedgerProduct::getIsProduction, true));
+            if (products.isEmpty()) {
+                log.info("閿�鍞彴璐{}]鏃犻渶鐢熶骇锛岃烦杩囩敓浜ф祦绋�", salesLedger.getSalesContractNo());
+                return;
+            }
+
+            // 妫�鏌ヤ骇鍝佹槸鍚﹀叿澶囧畬鏁寸殑宸ヨ壓鏁版嵁锛堝伐鑹鸿矾绾裤�佸伐搴忋�丅OM锛�
+            List<Long> missingTechProductIds = checkTechnologyDataReadiness(products);
+            if (!missingTechProductIds.isEmpty()) {
+                log.warn("閿�鍞彴璐{}]浠ヤ笅浜у搧缂哄皯宸ヨ壓鏁版嵁锛堝伐鑹鸿矾绾�/宸ュ簭/BOM锛夛紝璺宠繃鐢熶骇娴佺▼: {}",
+                        salesLedger.getSalesContractNo(), missingTechProductIds);
+                return;
+            }
+
+            // 2. 鐢熶骇璁″垝鍚堝苟涓嬪彂 鈫� 鐢熶骇璁㈠崟
+            LocalDate planDate = baseDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
+            processProductionCombine(salesLedger, planDate);
+
+            // 3. 棰嗘枡锛堢墿鏂欎笉瓒宠嚜鍔ㄥ叆搴撳悗鍐嶉锛�
+            LocalDate pickDate = planDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3));
+            processMaterialPick(salesLedger, pickDate);
+
+            // 4. 鐢熶骇鎶ュ伐
+            LocalDate reportDate = pickDate.plusDays(ThreadLocalRandom.current().nextInt(1, 4));
+            processProductionReport(salesLedger, reportDate);
+
+            // 5. 璐ㄦ鎻愪氦 + 鍏ュ簱瀹℃壒
+            LocalDate qualityDate = reportDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
+            processSalesQualityAndStockIn(salesLedger, qualityDate);
+
+            // 6. 鍙戣揣 + 鍙戣揣瀹℃壒 + 鍑哄簱瀹℃壒
+            LocalDate shipDate = qualityDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
+            processSalesShipping(salesLedger, shipDate);
+
+            log.info("閿�鍞彴璐{}]瀹屾暣娴佺▼澶勭悊瀹屾瘯", salesLedger.getSalesContractNo());
+        } catch (Exception e) {
+            log.warn("閿�鍞畬鏁存祦绋嬪鐞嗗け璐{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
+        }
+    }
+
+    /**
+     * 鏌ヨ瑙掕壊鎴栭儴闂ㄥ惈鎸囧畾鍏抽敭瀛楃殑鐢ㄦ埛锛岄殢鏈鸿繑鍥炰竴涓�
+     */
+    private SysUser randomUserByKeyword(String keyword) {
+        try {
+            List<Long> userIds = new ArrayList<>(sysUserMapper.getUserByRole(keyword));
+
+            List<SysDept> depts = sysDeptMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SysDept>()
+                            .like(SysDept::getDeptName, keyword)
+                            .eq(SysDept::getDelFlag, "0")
+                            .eq(SysDept::getStatus, "0"));
+            if (!depts.isEmpty()) {
+                List<Long> deptIds = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
+                List<Long> deptUserIds = sysUserDeptMapper.selectDistinctUserIdsByDeptIds(deptIds);
+                userIds.addAll(deptUserIds);
+            }
+
+            if (userIds.isEmpty()) {
+                return null;
+            }
+            List<Long> distinctIds = userIds.stream().distinct().collect(Collectors.toList());
+            Long randomId = distinctIds.get(ThreadLocalRandom.current().nextInt(distinctIds.size()));
+            return sysUserMapper.selectUserById(randomId);
+        } catch (Exception e) {
+            log.warn("鏌ヨ[{}]瑙掕壊/閮ㄩ棬鐢ㄦ埛澶辫触: {}", keyword, e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 鏌ヨ瑙掕壊鎴栭儴闂ㄥ惈"鐢熶骇"鐨勭敤鎴凤紝闅忔満杩斿洖涓�涓�
+     */
+    private SysUser randomProductionUser() {
+        return randomUserByKeyword("鐢熶骇");
+    }
+
+    /**
+     * 妫�鏌ヤ骇鍝佹槸鍚﹀叿澶囧畬鏁寸殑宸ヨ壓鏁版嵁锛堝伐鑹鸿矾绾裤�佸伐搴忋�丅OM锛�
+     * @return 缂哄皯宸ヨ壓鏁版嵁鐨勪骇鍝佽鏍糏D鍒楄〃锛堢┖鍒楄〃琛ㄧず鍏ㄩ儴灏辩华锛�
+     */
+    private List<Long> checkTechnologyDataReadiness(List<SalesLedgerProduct> products) {
+        List<Long> missingIds = new ArrayList<>();
+        for (SalesLedgerProduct slp : products) {
+            Long productModelId = slp.getProductModelId();
+            if (productModelId == null) continue;
+
+            // 1. 妫�鏌ュ伐鑹鸿矾绾�
+            List<com.ruoyi.technology.pojo.TechnologyRouting> routings =
+                    technologyRoutingMapper.selectList(
+                            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.technology.pojo.TechnologyRouting>()
+                                    .eq(com.ruoyi.technology.pojo.TechnologyRouting::getProductModelId, productModelId));
+            if (routings.isEmpty()) {
+                log.warn("浜у搧瑙勬牸[{}]缂哄皯宸ヨ壓璺嚎", productModelId);
+                missingIds.add(productModelId);
+                continue;
+            }
+            Long routingId = routings.get(0).getId();
+
+            // 2. 妫�鏌ュ伐鑹鸿矾绾挎槸鍚︽湁鍏宠仈宸ュ簭
+            List<com.ruoyi.technology.pojo.TechnologyRoutingOperation> routingOps =
+                    technologyRoutingOperationMapper.selectList(
+                            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.technology.pojo.TechnologyRoutingOperation>()
+                                    .eq(com.ruoyi.technology.pojo.TechnologyRoutingOperation::getTechnologyRoutingId, routingId));
+            if (routingOps.isEmpty()) {
+                log.warn("浜у搧瑙勬牸[{}]宸ヨ壓璺嚎[{}]缂哄皯宸ュ簭", productModelId, routingId);
+                missingIds.add(productModelId);
+                continue;
+            }
+
+            // 3. 妫�鏌OM锛堝彲閫変絾鏈夋洿濂斤級
+            com.ruoyi.technology.pojo.TechnologyRouting routing = routings.get(0);
+            if (routing.getBomId() != null) {
+                List<com.ruoyi.technology.pojo.TechnologyBomStructure> bomStructures =
+                        technologyBomStructureMapper.selectList(
+                                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.technology.pojo.TechnologyBomStructure>()
+                                        .eq(com.ruoyi.technology.pojo.TechnologyBomStructure::getBomId, routing.getBomId()));
+                if (bomStructures.isEmpty()) {
+                    log.warn("浜у搧瑙勬牸[{}]BOM[{}]缂哄皯浜у搧缁撴瀯", productModelId, routing.getBomId());
+                    missingIds.add(productModelId);
+                }
+            }
+        }
+        return missingIds;
+    }
+
+    /**
+     * 鐢熶骇璁″垝鍚堝苟涓嬪彂 鈫� 鐢熶骇璁㈠崟锛堟寜productModelId鍒嗙粍锛屽悓鍨嬪彿鍚堝苟涓嬪彂锛�
+     */
+    private void processProductionCombine(SalesLedger salesLedger, LocalDate planDate) {
+        try {
+            List<ProductionPlan> plans = productionPlanMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionPlan>()
+                            .eq(ProductionPlan::getSalesLedgerId, salesLedger.getId())
+                            .and(w -> w.eq(ProductionPlan::getStatus, 0).or().isNull(ProductionPlan::getStatus)));
+            if (plans.isEmpty()) {
+                log.info("閿�鍞彴璐{}]鏃犲緟涓嬪彂鐢熶骇璁″垝", salesLedger.getSalesContractNo());
+                return;
+            }
+
+            // 鎸塸roductModelId鍒嗙粍锛屽悓鍨嬪彿鎵嶈兘鍚堝苟涓嬪彂锛沺roductModelId涓簄ull鐨勫崟鐙�愪釜涓嬪彂
+            Map<Long, List<ProductionPlan>> grouped = plans.stream()
+                    .filter(p -> p.getProductModelId() != null)
+                    .collect(Collectors.groupingBy(ProductionPlan::getProductModelId));
+
+            for (Map.Entry<Long, List<ProductionPlan>> entry : grouped.entrySet()) {
+                try {
+                    List<ProductionPlan> sameModelPlans = entry.getValue();
+                    BigDecimal totalQty = sameModelPlans.stream()
+                            .map(p -> Optional.ofNullable(p.getQtyRequired()).orElse(BigDecimal.ZERO))
+                            .reduce(BigDecimal.ZERO, BigDecimal::add);
+                    ProductionPlanDto combineDto = new ProductionPlanDto();
+                    combineDto.setIds(sameModelPlans.stream().map(ProductionPlan::getId).collect(Collectors.toList()));
+                    combineDto.setTotalAssignedQuantity(totalQty);
+                    combineDto.setPlanCompleteTime(planDate.plusDays(ThreadLocalRandom.current().nextInt(3, 7)));
+                    productionPlanService.combine(combineDto);
+
+                    // 淇鐢熶骇璁㈠崟鐨刾lanCompleteTime
+                    List<ProductionOrder> orders = productionOrderMapper.selectList(
+                            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionOrder>()
+                                    .like(ProductionOrder::getProductionPlanIds, String.valueOf(sameModelPlans.get(0).getId())));
+                    for (ProductionOrder order : orders) {
+                        order.setPlanCompleteTime(planDate.plusDays(ThreadLocalRandom.current().nextInt(3, 7)));
+                        order.setStartTime(planDate.atStartOfDay());
+                        productionOrderMapper.updateById(order);
+                    }
+                    log.info("閿�鍞彴璐{}]鐢熶骇璁″垝涓嬪彂鎴愬姛, productModelId={}, 璁″垝鏁�: {}",
+                            salesLedger.getSalesContractNo(), entry.getKey(), sameModelPlans.size());
+                } catch (Exception e) {
+                    log.warn("閿�鍞彴璐{}]鐢熶骇璁″垝涓嬪彂澶辫触, productModelId={}: {}",
+                            salesLedger.getSalesContractNo(), entry.getKey(), e.getMessage());
+                }
+            }
+        } catch (Exception e) {
+            log.warn("鐢熶骇璁″垝涓嬪彂澶辫触[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
+        }
+    }
+
+    /**
+     * 棰嗘枡: 鏌ヨ鐢熶骇璁㈠崟鐨凚OM棰嗘枡娓呭崟锛屾鏌ュ簱瀛橈紝涓嶈冻鍒欏厛鑷姩鍏ュ簱瀹℃壒鍚庡啀棰嗘枡
+     */
+    private void processMaterialPick(SalesLedger salesLedger, LocalDate pickDate) {
+        try {
+            List<ProductionOrder> orders = findOrdersForSalesLedger(salesLedger);
+            if (orders.isEmpty()) {
+                log.info("閿�鍞彴璐{}]鏃犵敓浜ц鍗曪紝璺宠繃棰嗘枡", salesLedger.getSalesContractNo());
+                return;
+            }
+
+            for (ProductionOrder order : orders) {
+                try {
+                    // 鏌ヨ璁㈠崟BOM棰嗘枡娓呭崟
+                    List<com.ruoyi.production.bean.vo.ProductionOrderPickVo> pickList = productionOrderService.pick(order.getId());
+                    if (pickList == null || pickList.isEmpty()) {
+                        log.info("鐢熶骇璁㈠崟[{}]鏃犻鏂欐竻鍗�", order.getId());
+                        continue;
+                    }
+
+                    // 妫�鏌ュ簱瀛樹笉瓒崇殑鐗╂枡锛屽厛鑷姩鍏ュ簱
+                    ensureMaterialStock(pickList, pickDate);
+
+                    // 閲嶆柊鑾峰彇棰嗘枡娓呭崟锛堝叆搴撳悗鎵瑰彿鍜屽簱瀛橀噺宸叉洿鏂帮級
+                    pickList = productionOrderService.pick(order.getId());
+                    if (pickList == null || pickList.isEmpty()) {
+                        log.info("鐢熶骇璁㈠崟[{}]閲嶆柊鑾峰彇棰嗘枡娓呭崟涓虹┖", order.getId());
+                        continue;
+                    }
+
+                    // 鎵ц棰嗘枡
+                    List<ProductionOrderPickDto> pickDtoList = new ArrayList<>();
+                    for (com.ruoyi.production.bean.vo.ProductionOrderPickVo pickVo : pickList) {
+                        ProductionOrderPickDto pickDto = new ProductionOrderPickDto();
+                        pickDto.setProductionOrderId(order.getId());
+                        pickDto.setProductModelId(pickVo.getProductModelId());
+                        pickDto.setPickQuantity(pickVo.getDemandedQuantity());
+                        pickDto.setPickType((byte) 1);
+                        pickDto.setOperationName(pickVo.getOperationName());
+                        pickDto.setTechnologyOperationId(pickVo.getTechnologyOperationId());
+                        pickDto.setDemandedQuantity(pickVo.getDemandedQuantity());
+                        pickDto.setBom(pickVo.getBom());
+                        // 璁剧疆鎵瑰彿锛堢敤鏇存柊鍚庣殑鎵瑰彿鍒楄〃锛�
+                        if (pickVo.getBatchNoList() != null && !pickVo.getBatchNoList().isEmpty()) {
+                            pickDto.setBatchNoList(pickVo.getBatchNoList());
+                            pickDto.setBatchNo(pickVo.getBatchNoList().get(0));
+                        }
+                        pickDtoList.add(pickDto);
+                    }
+
+                    if (!pickDtoList.isEmpty()) {
+                        ProductionOrderPickDto batchDto = new ProductionOrderPickDto();
+                        batchDto.setPickList(pickDtoList);
+                        productionOrderPickService.savePick(batchDto);
+                        log.info("鐢熶骇璁㈠崟[{}]棰嗘枡鎴愬姛, 棰嗘枡椤规暟: {}", order.getId(), pickDtoList.size());
+                    }
+                } catch (Exception e) {
+                    log.warn("鐢熶骇璁㈠崟[{}]棰嗘枡澶辫触: {}", order.getId(), e.getMessage());
+                }
+            }
+        } catch (Exception e) {
+            log.warn("棰嗘枡娴佺▼澶辫触[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
+        }
+    }
+
+    /**
+     * 纭繚鐗╂枡搴撳瓨鍏呰冻锛屼笉瓒冲垯鍏堣嚜鍔ㄥ叆搴撳鎵�
+     */
+    private void ensureMaterialStock(List<com.ruoyi.production.bean.vo.ProductionOrderPickVo> pickList, LocalDate pickDate) {
+        LocalDateTime pickDateTime = pickDate.atTime(9, 0, 0).plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
+        String pickDateStr = pickDate.format(DateTimeFormatter.BASIC_ISO_DATE);
+
+        for (com.ruoyi.production.bean.vo.ProductionOrderPickVo pickVo : pickList) {
+            BigDecimal demanded = pickVo.getDemandedQuantity() != null ? pickVo.getDemandedQuantity() : BigDecimal.ZERO;
+            BigDecimal stockQty = pickVo.getStockQuantity() != null ? pickVo.getStockQuantity() : BigDecimal.ZERO;
+            BigDecimal shortage = demanded.subtract(stockQty);
+
+            if (shortage.compareTo(BigDecimal.ZERO) <= 0) {
+                continue; // 搴撳瓨鍏呰冻
+            }
+
+            // 搴撳瓨涓嶈冻锛岃嚜鍔ㄥ叆搴撹ˉ鍏�
+            try {
+                StockInventoryDto dto = new StockInventoryDto();
+                dto.setProductModelId(pickVo.getProductModelId());
+                dto.setQualitity(shortage);
+                dto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode());
+                dto.setRecordId(0L);
+                stockInventoryService.addStockInRecordOnly(dto);
+
+                // 鏌ユ壘鍒氬垱寤虹殑鍏ュ簱璁板綍
+                List<com.ruoyi.stock.pojo.StockInRecord> records = stockInRecordService.list(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.ruoyi.stock.pojo.StockInRecord>()
+                                .eq(com.ruoyi.stock.pojo.StockInRecord::getProductModelId, pickVo.getProductModelId())
+                                .eq(com.ruoyi.stock.pojo.StockInRecord::getApprovalStatus, 0)
+                                .orderByDesc(com.ruoyi.stock.pojo.StockInRecord::getId)
+                                .last("limit 1"));
+                if (!records.isEmpty()) {
+                    com.ruoyi.stock.pojo.StockInRecord record = records.get(0);
+                    record.setCreateTime(pickDateTime);
+                    record.setBatchNo(fixBatchNoDate(record.getBatchNo(), pickDateStr));
+                    record.setInboundBatches(fixBatchNoDate(record.getInboundBatches(), pickDateStr));
+                    stockInRecordMapper.updateById(record);
+                    // 瀹℃壒閫氳繃
+                    stockInRecordService.batchApprove(List.of(record.getId()), ReviewStatusEnum.APPROVED.getCode());
+                    log.info("鐗╂枡[{}]鑷姩鍏ュ簱瀹℃壒瀹屾垚, 鍏ュ簱鏁伴噺: {}", pickVo.getProductModelId(), shortage);
+                }
+            } catch (Exception e) {
+                log.warn("鐗╂枡[{}]鑷姩鍏ュ簱澶辫触: {}", pickVo.getProductModelId(), e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * 鐢熶骇鎶ュ伐: 閬嶅巻宸ュ崟閫愪釜鎶ュ伐锛屼粠鐢熶骇瑙掕壊鐢ㄦ埛涓殢鏈洪�夊彇鎶ュ伐浜�
+     */
+    private void processProductionReport(SalesLedger salesLedger, LocalDate reportDate) {
+        try {
+            List<ProductionOrder> orders = findOrdersForSalesLedger(salesLedger);
+            if (orders.isEmpty()) {
+                log.info("閿�鍞彴璐{}]鏃犵敓浜ц鍗�", salesLedger.getSalesContractNo());
+                return;
+            }
+
+            for (ProductionOrder order : orders) {
+                List<ProductionOperationTask> tasks = productionOperationTaskMapper.selectList(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionOperationTask>()
+                                .eq(ProductionOperationTask::getProductionOrderId, order.getId())
+                                .orderByAsc(ProductionOperationTask::getId));
+                for (ProductionOperationTask task : tasks) {
+                    if (task.getStatus() != null && task.getStatus() >= 3) continue;
+
+                    // 姣忔鎶ュ伐闅忔満閫変竴涓敓浜х敤鎴�
+                    SysUser productionUser = randomProductionUser();
+                    Long userId = productionUser != null ? productionUser.getUserId() : 1L;
+                    String userName = productionUser != null ? productionUser.getNickName() : "绯荤粺";
+
+                    // 鎶ュ伐
+                    ProductionProductMainDto reportDto = new ProductionProductMainDto();
+                    reportDto.setProductionOperationTaskId(task.getId());
+                    reportDto.setQuantity(task.getPlanQuantity());
+                    reportDto.setScrapQty(BigDecimal.ZERO);
+                    reportDto.setUserId(userId);
+                    reportDto.setUserName(userName);
+                    productionProductMainService.addProductMain(reportDto);
+
+                    // 淇鎶ュ伐鏃堕棿锛堥噸鏂颁粠DB璇诲彇锛岄伩鍏嶈鐩朼ddProductMain鏇存柊鐨刢ompleteQuantity锛�
+                    fixProductionReportTimes(task.getId(), reportDate);
+                }
+                // 淇鐢熶骇璁㈠崟鏃堕棿锛堥噸鏂颁粠DB璇诲彇锛岄伩鍏嶈鐩朼ddProductMain鏇存柊鐨刢ompleteQuantity锛�
+                fixProductionOrderTimes(order.getId(), reportDate);
+            }
+            log.info("閿�鍞彴璐{}]鐢熶骇鎶ュ伐瀹屾垚, 璁㈠崟鏁�: {}", salesLedger.getSalesContractNo(), orders.size());
+        } catch (Exception e) {
+            log.warn("鐢熶骇鎶ュ伐澶辫触[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
+        }
+    }
+
+    /**
+     * 鏌ユ壘閿�鍞彴璐﹀叧鑱旂殑鐢熶骇璁㈠崟
+     */
+    private List<ProductionOrder> findOrdersForSalesLedger(SalesLedger salesLedger) {
+        List<ProductionOrder> orders = new ArrayList<>();
+        List<ProductionPlan> plans = productionPlanMapper.selectList(
+                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionPlan>()
+                        .eq(ProductionPlan::getSalesLedgerId, salesLedger.getId()));
+        for (ProductionPlan plan : plans) {
+            List<ProductionOrder> po = productionOrderMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ProductionOrder>()
+                            .like(ProductionOrder::getProductionPlanIds, String.valueOf(plan.getId())));
+            orders.addAll(po);
+        }
+        // 鍘婚噸
+        return orders.stream()
+                .collect(Collectors.toMap(ProductionOrder::getId, o -> o, (a, b) -> a))
+                .values().stream().collect(Collectors.toList());
+    }
+
+    /**
+     * 淇鐢熶骇鎶ュ伐鐩稿叧鏃堕棿锛堥噸鏂颁粠DB璇诲彇task锛岄伩鍏嶈鐩朼ddProductMain宸叉洿鏂扮殑completeQuantity锛�
+     */
+    private void fixProductionReportTimes(Long taskId, LocalDate reportDate) {
+        try {
+            ProductionOperationTask freshTask = productionOperationTaskMapper.selectById(taskId);
+            if (freshTask != null) {
+                freshTask.setActualStartTime(reportDate);
+                freshTask.setActualEndTime(reportDate);
+                freshTask.setStatus(4);
+                productionOperationTaskMapper.updateById(freshTask);
+            }
+        } catch (Exception e) {
+            log.warn("淇鐢熶骇鎶ュ伐鏃堕棿澶辫触: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 淇鐢熶骇璁㈠崟鏃堕棿锛堥噸鏂颁粠DB璇诲彇order锛岄伩鍏嶈鐩朼ddProductMain宸叉洿鏂扮殑completeQuantity锛�
+     */
+    private void fixProductionOrderTimes(Long orderId, LocalDate reportDate) {
+        try {
+            ProductionOrder freshOrder = productionOrderMapper.selectById(orderId);
+            if (freshOrder != null) {
+                freshOrder.setStartTime(reportDate.minusDays(1).atStartOfDay());
+                freshOrder.setEndTime(reportDate.plusDays(1).atStartOfDay());
+                freshOrder.setStatus(3);
+                productionOrderMapper.updateById(freshOrder);
+            }
+        } catch (Exception e) {
+            log.warn("淇鐢熶骇璁㈠崟鏃堕棿澶辫触: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 閿�鍞川妫�鎻愪氦 + 鍏ュ簱瀹℃壒
+     */
+    private void processSalesQualityAndStockIn(SalesLedger salesLedger, LocalDate qualityDate) {
+        try {
+            LocalDateTime qualityDateTime = qualityDate.atTime(9, 0, 0)
+                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
+
+            // 鏌ユ墍鏈夋湭鎻愪氦鐨勮川妫�鍗曪紙inspectType=1杩囩▼妫�楠�, 2=鍑哄巶妫�楠岋紝鐢辩敓浜ф姤宸ョ敓鎴愶級
+            List<QualityInspect> allUnsubmitted = qualityInspectService.list(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<QualityInspect>()
+                            .eq(QualityInspect::getInspectState, 0)
+                            .in(QualityInspect::getInspectType, java.util.Arrays.asList(1, 2)));
+            for (QualityInspect qi : allUnsubmitted) {
+                qualityInspectService.autoSubmit(qi.getId());
+                qi.setCreateTime(qualityDateTime);
+                qualityInspectMapper.updateById(qi);
+            }
+            log.info("閿�鍞彴璐{}]璐ㄦ鎻愪氦瀹屾垚, 璐ㄦ鍗曟暟: {}", salesLedger.getSalesContractNo(), allUnsubmitted.size());
+
+            // 鍏ュ簱瀹℃壒锛氬鎵规墍鏈夊緟瀹℃壒鐨勫叆搴撹褰�
+            LocalDate stockDate = qualityDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3));
+            LocalDateTime stockDateTime = stockDate.atTime(9, 0, 0)
+                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
+            String stockDateStr = stockDate.format(DateTimeFormatter.BASIC_ISO_DATE);
+            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::getApprovalStatus, 0));
+            List<Long> recordIds = stockRecords.stream()
+                    .map(com.ruoyi.stock.pojo.StockInRecord::getId)
+                    .collect(Collectors.toList());
+            if (!recordIds.isEmpty()) {
+                for (com.ruoyi.stock.pojo.StockInRecord sr : stockRecords) {
+                    sr.setCreateTime(stockDateTime);
+                    sr.setBatchNo(fixBatchNoDate(sr.getBatchNo(), stockDateStr));
+                    sr.setInboundBatches(fixBatchNoDate(sr.getInboundBatches(), stockDateStr));
+                    stockInRecordMapper.updateById(sr);
+                }
+                stockInRecordService.batchApprove(recordIds, ReviewStatusEnum.APPROVED.getCode());
+                for (com.ruoyi.stock.pojo.StockInRecord sr : stockRecords) {
+                    StockInventory si = stockInventoryMapper.selectOne(
+                            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockInventory>()
+                                    .eq(StockInventory::getProductModelId, sr.getProductModelId())
+                                    .eq(StockInventory::getBatchNo, sr.getBatchNo()));
+                    if (si != null) {
+                        si.setBatchNo(fixBatchNoDate(si.getBatchNo(), stockDateStr));
+                        stockInventoryMapper.updateById(si);
+                    }
+                }
+                log.info("閿�鍞彴璐{}]鍏ュ簱瀹℃壒瀹屾垚, 鍏ュ簱璁板綍鏁�: {}", salesLedger.getSalesContractNo(), recordIds.size());
+            }
+        } catch (Exception e) {
+            log.warn("閿�鍞川妫�鍏ュ簱澶辫触[{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
+        }
+    }
+
+    /**
+     * 鍙戣揣 + 鍙戣揣瀹℃壒閫氳繃 + 鍑哄簱瀹℃壒
+     */
+    private void processSalesShipping(SalesLedger salesLedger, LocalDate shipDate) {
+        try {
+            LocalDateTime shipDateTime = shipDate.atTime(9, 0, 0)
+                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
+            String shipDateStr = shipDate.format(DateTimeFormatter.BASIC_ISO_DATE);
+
+            // 鏌ユ壘鏈夊簱瀛樼殑浜у搧瑙勬牸
+            List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SalesLedgerProduct>()
+                            .eq(SalesLedgerProduct::getSalesLedgerId, salesLedger.getId()));
+
+            List<ShippingProductDetail> details = new ArrayList<>();
+            for (SalesLedgerProduct slp : products) {
+                StockInventory si = stockInventoryMapper.selectOne(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockInventory>()
+                                .eq(StockInventory::getProductModelId, slp.getProductModelId())
+                                .gt(StockInventory::getQualitity, BigDecimal.ZERO)
+                                .orderByDesc(StockInventory::getId)
+                                .last("limit 1"));
+                if (si != null) {
+                    ShippingProductDetail detail = new ShippingProductDetail();
+                    detail.setStockInventoryId(si.getId());
+                    detail.setProductModelId(slp.getProductModelId());
+                    detail.setBatchNo(si.getBatchNo());
+                    detail.setQuantity(slp.getQuantity());
+                    details.add(detail);
+                }
+            }
+            if (details.isEmpty()) {
+                log.info("閿�鍞彴璐{}]鏃犲彲鐢ㄥ簱瀛橈紝璺宠繃鍙戣揣", salesLedger.getSalesContractNo());
+                return;
+            }
+
+            // 鍒涘缓鍙戣揣鍗�
+            ShippingInfoDto shipDto = new ShippingInfoDto();
+            shipDto.setSalesLedgerId(salesLedger.getId());
+            shipDto.setSalesLedgerProductId(products.get(0).getId());
+            shipDto.setCreateTime(shipDateTime);
+            shipDto.setBatchNoDetailList(details);
+            shippingInfoService.addReq(shipDto);
+
+            // 鎵惧埌鍙戣揣鍗曞拰瀹℃壒瀹炰緥
+            ShippingInfo shippingInfo = shippingInfoMapper.selectOne(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ShippingInfo>()
+                            .eq(ShippingInfo::getShippingNo, shipDto.getShippingNo())
+                            .last("limit 1"));
+            if (shippingInfo != null) {
+                shippingInfo.setCreateTime(shipDateTime);
+                shippingInfo.setShippingDate(java.sql.Date.valueOf(shipDate));
+                // 鏍规嵁瀹㈡埛鍦板潃鐢熸垚鍙戣揣杞︾墝鍙�
+                shippingInfo.setShippingCarNumber(generateCarNumber(salesLedger.getCustomerName()));
+                shippingInfoMapper.updateById(shippingInfo);
+
+                // 鍙戣揣瀹℃壒鑷姩閫氳繃
+                ApprovalInstance shipApproval = approvalInstanceMapper.selectOne(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstance>()
+                                .eq(ApprovalInstance::getBusinessId, shippingInfo.getId())
+                                .eq(ApprovalInstance::getBusinessType, 7L)
+                                .eq(ApprovalInstance::getDeleted, 0)
+                                .orderByDesc(ApprovalInstance::getId)
+                                .last("limit 1"));
+                if (shipApproval != null) {
+                    LocalDate shipApproveDate = shipDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3));
+                    LocalDateTime shipApproveDateTime = shipApproveDate.atTime(9, 0, 0)
+                            .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
+                    approvalInstanceService.autoApprove(shipApproval.getId());
+                    fixApprovalTimes(shipApproval.getId(), shipApproveDateTime);
+
+                    shippingInfo.setStatus("宸插彂璐�");
+                    shippingInfo.setShippingDate(java.sql.Date.valueOf(shipApproveDate));
+                    shippingInfoMapper.updateById(shippingInfo);
+                }
+
+                // 鍑哄簱瀹℃壒
+                LocalDate outDate = shipDate.plusDays(ThreadLocalRandom.current().nextInt(0, 3));
+                LocalDateTime outDateTime = outDate.atTime(9, 0, 0)
+                        .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
+                String outDateStr = outDate.format(DateTimeFormatter.BASIC_ISO_DATE);
+                List<StockOutRecord> outRecords = stockOutRecordMapper.selectList(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StockOutRecord>()
+                                .eq(StockOutRecord::getRecordId, shippingInfo.getId())
+                                .eq(StockOutRecord::getRecordType,
+                                        String.valueOf(StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode())));
+                List<Long> outIds = new ArrayList<>();
+                for (StockOutRecord sr : outRecords) {
+                    if (sr.getApprovalStatus() == null || sr.getApprovalStatus() == 0 || sr.getApprovalStatus() == 3) {
+                        sr.setCreateTime(outDateTime);
+                        sr.setOutboundBatches(fixBatchNoDate(sr.getOutboundBatches(), outDateStr));
+                        sr.setBatchNo(fixBatchNoDate(sr.getBatchNo(), outDateStr));
+                        stockOutRecordMapper.updateById(sr);
+                        outIds.add(sr.getId());
+                    }
+                }
+                if (!outIds.isEmpty()) {
+                    // 鍑哄簱瀹℃壒閫氳繃锛堣蛋姝e紡瀹℃壒娴佺▼锛屽唴閮ㄤ細鎵e噺搴撳瓨锛�
+                    stockOutRecordService.batchApprove(outIds, ReviewStatusEnum.APPROVED.getCode());
+                    log.info("閿�鍞彴璐{}]鍑哄簱瀹℃壒瀹屾垚, 鍑哄簱璁板綍鏁�: {}",
+                            salesLedger.getSalesContractNo(), outIds.size());
+                }
+            }
+            log.info("閿�鍞彴璐{}]鍙戣揣娴佺▼瀹屾垚", salesLedger.getSalesContractNo());
+        } catch (Exception e) {
+            log.warn("閿�鍞彂璐ф祦绋嬪け璐{}]: {}", salesLedger.getSalesContractNo(), e.getMessage());
+        }
+    }
+
     private ModuleSummary createPurchaseLedgers(List<JSONObject> items, Map<String, Long> supplierNameToId,
-                                                 String additionalInfo, String dateEnd) {
+                                                 String additionalInfo, String dateStart, String dateEnd) {
         // 鏄惁闇�瑕佽川妫�锛屼粠琛ュ厖淇℃伅鍒ゆ柇锛岄粯璁や笉闇�瑕�
         boolean needQualityInspect = additionalInfo != null
                 && (additionalInfo.contains("璐ㄦ") || additionalInfo.contains("闇�瑕佹楠�"));
@@ -396,12 +1246,19 @@
 
                 String entryDateStr = item.getString("entryDate");
                 LocalDate entryDate = null;
-                if (item.containsKey("entryDate")) {
+                if (item.containsKey("entryDate") && entryDateStr != null && entryDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
                     entryDate = LocalDate.parse(entryDateStr);
                     dto.setEntryDate(java.sql.Date.valueOf(entryDateStr));
+                } else {
+                    dto.setEntryDate(java.sql.Date.valueOf(dateStart));
                 }
                 if (item.containsKey("executionDate")) {
-                    dto.setExecutionDate(java.sql.Date.valueOf(item.getString("executionDate")));
+                    String execDateStr = item.getString("executionDate");
+                    if (execDateStr != null && execDateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                        dto.setExecutionDate(java.sql.Date.valueOf(execDateStr));
+                    } else {
+                        dto.setExecutionDate(java.sql.Date.valueOf(dateStart));
+                    }
                 }
                 JSONArray productData = item.getJSONArray("productData");
                 if (productData != null) {
@@ -445,7 +1302,7 @@
                 }
                 success++;
             } catch (Exception e) {
-                log.warn("鍒涘缓閲囪喘鍙拌处澶辫触: {}", e.getMessage());
+                log.warn("鍒涘缓閲囪喘鍙拌处澶辫触: {}", e.getMessage(), e);
                 fail++;
             }
         }
@@ -454,10 +1311,18 @@
 
     /**
      * 閲囪喘瀹屾暣娴佺▼: 瀹℃牳閫氳繃 鈫� 璐ㄦ(鍙��) 鈫� 鍏ュ簱瀹℃牳閫氳繃
+     * 鍚勭幆鑺傛椂闂翠互閲囪喘褰曞叆鏃ユ湡涓哄熀鍑嗭紝鍋跺皵鎺ㄨ繜1-3澶�
      */
     private void processPurchaseFullFlow(PurchaseLedger purchaseLedger, boolean needQualityInspect,
                                           LocalDate entryDate, String dateEnd) {
         try {
+            // 鍩哄噯鏃ユ湡锛氶噰璐綍鍏ユ棩鏈燂紝涓虹┖鍒欑敤褰撳ぉ
+            LocalDate baseDate = entryDate != null ? entryDate : LocalDate.now();
+            // 瀹℃壒鏃堕棿锛氬熀浜庡綍鍏ユ棩鏈燂紝闅忔満鎺�0-3澶�
+            LocalDate approveDate = baseDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
+            LocalDateTime approveDateTime = approveDate.atTime(9, 0, 0)
+                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
+
             // 1. 瀹℃壒鑷姩閫氳繃
             ApprovalInstance approvalInstance = approvalInstanceMapper.selectOne(
                     new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstance>()
@@ -467,21 +1332,25 @@
                             .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());
+                // 淇瀹℃壒鐩稿叧鏃堕棿涓洪噰璐綍鍏ユ棩鏈熻寖鍥�
+                fixApprovalTimes(approvalInstance.getId(), approveDateTime);
                 log.info("閲囪喘鍙拌处[{}]瀹℃壒閫氳繃, 瀹℃壒鏃ユ湡: {}", purchaseLedger.getPurchaseContractNumber(), approveDate);
             }
 
             // 2. 璐ㄦ娴佺▼锛堝鏋滈渶瑕佽川妫�锛�
             if (needQualityInspect) {
-                processQualityInspect(purchaseLedger, entryDate, dateEnd);
+                // 璐ㄦ鏃堕棿锛氬鎵逛箣鍚庡啀鎺�0-3澶�
+                LocalDate inspectDate = approveDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
+                processQualityInspect(purchaseLedger, inspectDate);
             }
 
             // 3. 鍏ュ簱瀹℃壒閫氳繃
-            processStockInApprove(purchaseLedger, dateEnd);
+            // 鍏ュ簱鏃堕棿锛氳川妫�鏃堕棿锛堟湁璐ㄦ锛夋垨瀹℃壒鏃堕棿涔嬪悗鍐嶆帹0-3澶�
+            LocalDate stockBaseDate = needQualityInspect
+                    ? approveDate.plusDays(ThreadLocalRandom.current().nextInt(1, 4))
+                    : approveDate.plusDays(ThreadLocalRandom.current().nextInt(0, 4));
+            processStockInApprove(purchaseLedger, stockBaseDate);
 
         } catch (Exception e) {
             log.warn("閲囪喘瀹屾暣娴佺▼澶勭悊澶辫触[{}]: {}", purchaseLedger.getPurchaseContractNumber(), e.getMessage());
@@ -489,17 +1358,68 @@
     }
 
     /**
+     * 淇瀹℃壒瀹炰緥鍙婂叧鑱旇妭鐐广�佷换鍔°�佽褰曠殑鏃堕棿
+     */
+    private void fixApprovalTimes(Long instanceId, LocalDateTime dateTime) {
+        try {
+            // 鏇存柊瀹℃壒瀹炰緥鐨刦inishTime鍜宑reateTime
+            ApprovalInstance instance = approvalInstanceMapper.selectById(instanceId);
+            if (instance != null) {
+                instance.setFinishTime(dateTime);
+                instance.setCreateTime(dateTime.minusHours(1));
+                approvalInstanceMapper.updateById(instance);
+            }
+
+            // 鏇存柊瀹℃壒瀹炰緥鑺傜偣鐨刦inishTime
+            List<ApprovalInstanceNode> nodes = approvalInstanceNodeMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalInstanceNode>()
+                            .eq(ApprovalInstanceNode::getInstanceId, instanceId));
+            for (ApprovalInstanceNode node : nodes) {
+                node.setFinishTime(dateTime);
+                node.setCreateTime(dateTime.minusHours(1));
+                approvalInstanceNodeMapper.updateById(node);
+            }
+
+            // 鏇存柊瀹℃壒浠诲姟鐨刢reateTime
+            List<ApprovalTask> tasks = approvalTaskMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalTask>()
+                            .eq(ApprovalTask::getInstanceId, instanceId));
+            for (ApprovalTask task : tasks) {
+                task.setCreateTime(dateTime.minusMinutes(30));
+                approvalTaskMapper.updateById(task);
+            }
+
+            // 鏇存柊瀹℃壒璁板綍鐨刢reateTime
+            List<ApprovalRecord> records = approvalRecordMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ApprovalRecord>()
+                            .eq(ApprovalRecord::getInstanceId, instanceId));
+            for (ApprovalRecord record : records) {
+                record.setCreateTime(dateTime.minusMinutes(10));
+                approvalRecordMapper.updateById(record);
+            }
+        } catch (Exception e) {
+            log.warn("淇瀹℃壒鏃堕棿澶辫触: {}", e.getMessage());
+        }
+    }
+
+    /**
      * 璐ㄦ: 鎵惧埌閲囪喘鍏宠仈鐨勮川妫�鍗曪紝鑷姩鎻愪氦涓哄悎鏍�
      */
-    private void processQualityInspect(PurchaseLedger purchaseLedger, LocalDate entryDate, String dateEnd) {
+    private void processQualityInspect(PurchaseLedger purchaseLedger, LocalDate inspectDate) {
         try {
+            LocalDateTime inspectDateTime = inspectDate.atTime(9, 0, 0)
+                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
             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());
+                    // 淇璐ㄦ鏃堕棿
+                    qi.setCreateTime(inspectDateTime);
+                    qualityInspectMapper.updateById(qi);
+                    log.info("閲囪喘鍙拌处[{}]璐ㄦ鍗昜{}]鑷姩鎻愪氦鍚堟牸, 璐ㄦ鏃ユ湡: {}",
+                            purchaseLedger.getPurchaseContractNumber(), qi.getId(), inspectDate);
                 }
             }
         } catch (Exception e) {
@@ -508,16 +1428,19 @@
     }
 
     /**
-     * 鍏ュ簱瀹℃牳: 鎵惧埌鍏ュ簱璁板綍骞跺鎵归�氳繃
+     * 鍏ュ簱瀹℃牳: 鎵惧埌鍏ュ簱璁板綍骞跺鎵归�氳繃锛屽苟淇鏃堕棿涓庢壒鍙锋棩鏈�
      */
-    private void processStockInApprove(PurchaseLedger purchaseLedger, String dateEnd) {
+    private void processStockInApprove(PurchaseLedger purchaseLedger, LocalDate stockDate) {
         try {
+            LocalDateTime stockDateTime = stockDate.atTime(9, 0, 0)
+                    .plusMinutes(ThreadLocalRandom.current().nextInt(0, 480));
+            String stockDateStr = stockDate.format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
+
             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>()
@@ -525,7 +1448,6 @@
                                 .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()))) {
@@ -534,7 +1456,6 @@
                                 .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());
@@ -545,8 +1466,20 @@
                         .map(com.ruoyi.stock.pojo.StockInRecord::getId)
                         .collect(Collectors.toList());
                 if (!recordIds.isEmpty()) {
+                    // 鍏堜慨姝e叆搴撹褰曠殑createTime鍜屾壒鍙锋棩鏈燂紙batchApprove鍐呴儴浼氱敤batchNo鍒涘缓StockInventory锛�
+                    for (Long recordId : recordIds) {
+                        com.ruoyi.stock.pojo.StockInRecord sr = stockInRecordMapper.selectById(recordId);
+                        if (sr != null) {
+                            sr.setCreateTime(stockDateTime);
+                            sr.setBatchNo(fixBatchNoDate(sr.getBatchNo(), stockDateStr));
+                            String s = OrderUtils.countTodayByCreateTime(stockInRecordMapper, "RK", "inbound_batches", stockDateTime);
+                            sr.setInboundBatches(s);
+                            stockInRecordMapper.updateById(sr);
+                        }
+                    }
                     stockInRecordService.batchApprove(recordIds, ReviewStatusEnum.APPROVED.getCode());
-                    log.info("閲囪喘鍙拌处[{}]鍏ュ簱瀹℃壒閫氳繃, 鍏ュ簱璁板綍鏁�: {}", purchaseLedger.getPurchaseContractNumber(), recordIds.size());
+                    log.info("閲囪喘鍙拌处[{}]鍏ュ簱瀹℃壒閫氳繃, 鍏ュ簱鏃ユ湡: {}, 鍏ュ簱璁板綍鏁�: {}",
+                            purchaseLedger.getPurchaseContractNumber(), stockDate, recordIds.size());
                 }
             }
         } catch (Exception e) {
@@ -554,8 +1487,137 @@
         }
     }
 
+    /**
+     * 鏇挎崲鎵瑰彿涓殑鏃ユ湡閮ㄥ垎锛坹yyyMMdd 鈫� 鎸囧畾鏃ユ湡锛�
+     */
+    /**
+     * 鏍规嵁瀹㈡埛鍚嶇О鏌ュ湴鍧�锛屾帹鏂渷浠界畝绉扮敓鎴愯溅鐗屽彿
+     * 鏍煎紡: 鐪佷唤绠�绉� + 瀛楁瘝 + 5浣嶉殢鏈烘暟瀛楀瓧姣�, 濡� 鑻廇12345
+     */
+    private String generateCarNumber(String customerName) {
+        // 鐪佷唤绠�绉板埌鍩庡競瀛楁瘝鐨勫父瑙佹槧灏�
+        Map<String, String[]> provinceCityMap = new HashMap<>();
+        provinceCityMap.put("浜�", new String[]{"A", "B", "C", "E", "F", "G"});
+        provinceCityMap.put("娌�", new String[]{"A", "B", "D", "E", "F"});
+        provinceCityMap.put("绮�", new String[]{"A", "B", "E", "F", "G", "H", "J", "K"});
+        provinceCityMap.put("鑻�", new String[]{"A", "B", "E", "F", "G", "H", "J", "K", "L", "M"});
+        provinceCityMap.put("娴�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L"});
+        provinceCityMap.put("椴�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "Y"});
+        provinceCityMap.put("璞�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "U"});
+        provinceCityMap.put("宸�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"});
+        provinceCityMap.put("娓�", new String[]{"A", "B", "C", "D"});
+        provinceCityMap.put("閯�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S"});
+        provinceCityMap.put("婀�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "S"});
+        provinceCityMap.put("闂�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K"});
+        provinceCityMap.put("璧�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M"});
+        provinceCityMap.put("鐨�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S"});
+        provinceCityMap.put("鍐�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "R", "T"});
+        provinceCityMap.put("杈�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P"});
+        provinceCityMap.put("鍚�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K"});
+        provinceCityMap.put("榛�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R"});
+        provinceCityMap.put("鏅�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M"});
+        provinceCityMap.put("闄�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "V"});
+        provinceCityMap.put("妗�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R"});
+        provinceCityMap.put("浜�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S"});
+        provinceCityMap.put("璐�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J"});
+        provinceCityMap.put("鐢�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P"});
+        provinceCityMap.put("鐞�", new String[]{"A", "B", "C", "D", "E", "F"});
+        provinceCityMap.put("瀹�", new String[]{"A", "B", "C", "D", "E"});
+        provinceCityMap.put("闈�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H"});
+        provinceCityMap.put("钘�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J"});
+        provinceCityMap.put("钂�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M"});
+        provinceCityMap.put("鏂�", new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R"});
+        provinceCityMap.put("娲�", new String[]{"A", "B", "C", "E", "F", "G", "H", "J", "K", "L", "M", "N", "Q", "R"});
+
+        // 鍦板潃鍏抽敭璇嶅埌鐪佷唤绠�绉扮殑鏄犲皠
+        Map<String, String> addressToProvince = new HashMap<>();
+        addressToProvince.put("鍖椾含", "浜�"); addressToProvince.put("涓婃捣", "娌�");
+        addressToProvince.put("骞垮窞", "绮�"); addressToProvince.put("娣卞湷", "绮�");
+        addressToProvince.put("涓滆帪", "绮�"); addressToProvince.put("浣涘北", "绮�");
+        addressToProvince.put("鍗椾含", "鑻�"); addressToProvince.put("鑻忓窞", "鑻�");
+        addressToProvince.put("鏃犻敗", "鑻�"); addressToProvince.put("鍗楅��", "鑻�");
+        addressToProvince.put("甯稿窞", "鑻�"); addressToProvince.put("寰愬窞", "鑻�");
+        addressToProvince.put("鏉窞", "娴�"); addressToProvince.put("瀹佹尝", "娴�");
+        addressToProvince.put("娓╁窞", "娴�"); addressToProvince.put("鍢夊叴", "娴�");
+        addressToProvince.put("娴庡崡", "椴�"); addressToProvince.put("闈掑矝", "椴�");
+        addressToProvince.put("閮戝窞", "璞�"); addressToProvince.put("鎴愰兘", "宸�");
+        addressToProvince.put("閲嶅簡", "娓�"); addressToProvince.put("姝︽眽", "閯�");
+        addressToProvince.put("闀挎矙", "婀�"); addressToProvince.put("绂忓窞", "闂�");
+        addressToProvince.put("鍘﹂棬", "闂�"); addressToProvince.put("鍗楁槍", "璧�");
+        addressToProvince.put("鍚堣偉", "鐨�"); addressToProvince.put("鐭冲搴�", "鍐�");
+        addressToProvince.put("娌堥槼", "杈�"); addressToProvince.put("澶ц繛", "杈�");
+        addressToProvince.put("闀挎槬", "鍚�"); addressToProvince.put("鍝堝皵婊�", "榛�");
+        addressToProvince.put("澶師", "鏅�"); addressToProvince.put("瑗垮畨", "闄�");
+        addressToProvince.put("鍗楀畞", "妗�"); addressToProvince.put("鏄嗘槑", "浜�");
+        addressToProvince.put("璐甸槼", "璐�"); addressToProvince.put("鍏板窞", "鐢�");
+        addressToProvince.put("娴峰彛", "鐞�"); addressToProvince.put("閾跺窛", "瀹�");
+        addressToProvince.put("瑗垮畞", "闈�"); addressToProvince.put("鎷夎惃", "钘�");
+        addressToProvince.put("鍛煎拰娴╃壒", "钂�"); addressToProvince.put("涔岄瞾鏈ㄩ綈", "鏂�");
+        addressToProvince.put("澶╂触", "娲�");
+        // 鐪佸悕鏄犲皠
+        addressToProvince.put("姹熻嫃", "鑻�"); addressToProvince.put("娴欐睙", "娴�");
+        addressToProvince.put("灞变笢", "椴�"); addressToProvince.put("娌冲崡", "璞�");
+        addressToProvince.put("鍥涘窛", "宸�"); addressToProvince.put("婀栧寳", "閯�");
+        addressToProvince.put("婀栧崡", "婀�"); addressToProvince.put("绂忓缓", "闂�");
+        addressToProvince.put("姹熻タ", "璧�"); addressToProvince.put("瀹夊窘", "鐨�");
+        addressToProvince.put("娌冲寳", "鍐�"); addressToProvince.put("杈藉畞", "杈�");
+        addressToProvince.put("鍚夋灄", "鍚�"); addressToProvince.put("榛戦緳姹�", "榛�");
+        addressToProvince.put("灞辫タ", "鏅�"); addressToProvince.put("闄曡タ", "闄�");
+        addressToProvince.put("骞夸笢", "绮�"); addressToProvince.put("骞胯タ", "妗�");
+        addressToProvince.put("浜戝崡", "浜�"); addressToProvince.put("璐靛窞", "璐�");
+        addressToProvince.put("鐢樿們", "鐢�"); addressToProvince.put("娴峰崡", "鐞�");
+        addressToProvince.put("瀹佸", "瀹�"); addressToProvince.put("闈掓捣", "闈�");
+        addressToProvince.put("瑗胯棌", "钘�"); addressToProvince.put("鍐呰挋鍙�", "钂�");
+        addressToProvince.put("鏂扮枂", "鏂�");
+
+        String province = "鑻�"; // 榛樿姹熻嫃
+        // 灏濊瘯浠庡鎴峰湴鍧�鎺ㄦ柇鐪佷唤
+        if (customerName != null) {
+            try {
+                Customer customer = customerService.getOne(
+                        new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<Customer>()
+                                .eq(Customer::getCustomerName, customerName)
+                                .last("limit 1"));
+                if (customer != null && customer.getCompanyAddress() != null) {
+                    String addr = customer.getCompanyAddress();
+                    for (Map.Entry<String, String> e : addressToProvince.entrySet()) {
+                        if (addr.contains(e.getKey())) {
+                            province = e.getValue();
+                            break;
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                log.debug("鏌ュ鎴峰湴鍧�澶辫触: {}", e.getMessage());
+            }
+        }
+
+        // 鐢熸垚杞︾墝鍙�: 鐪佷唤绠�绉� + 鍩庡競瀛楁瘝 + 5浣嶉殢鏈哄瓧绗�(鏁板瓧+澶у啓瀛楁瘝)
+        String[] cities = provinceCityMap.getOrDefault(province, new String[]{"A", "B", "C"});
+        String city = cities[ThreadLocalRandom.current().nextInt(cities.length)];
+        String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ0123456789";
+        StringBuilder suffix = new StringBuilder();
+        for (int i = 0; i < 5; i++) {
+            suffix.append(chars.charAt(ThreadLocalRandom.current().nextInt(chars.length())));
+        }
+        return province + city + suffix;
+    }
+
+    private String fixBatchNoDate(String batchNo, String newDate) {
+        if (batchNo == null || batchNo.length() < 8) {
+            return batchNo;
+        }
+        // 鎵瑰彿鏍煎紡: yyyyMMdd-浜у搧缂栫爜-NNN
+        String prefix = batchNo.substring(0, 8);
+        if (prefix.matches("\\d{8}")) {
+            return newDate + batchNo.substring(8);
+        }
+        return batchNo;
+    }
+
     private ModuleSummary createProductionPlans(List<JSONObject> items) {
         int success = 0, fail = 0;
+        List<ProductionPlan> createdPlans = new ArrayList<>();
         for (JSONObject item : items) {
             try {
                 ProductionPlan plan = new ProductionPlan();
@@ -564,18 +1626,48 @@
                 plan.setSource(item.getString("source"));
                 plan.setRemark(item.getString("remark"));
                 if (item.containsKey("requiredDate")) {
-                    plan.setRequiredDate(LocalDate.parse(item.getString("requiredDate")));
+                    String dateStr = item.getString("requiredDate");
+                    if (dateStr != null && dateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                        plan.setRequiredDate(LocalDate.parse(dateStr));
+                    }
                 }
                 if (item.containsKey("promisedDeliveryDate")) {
-                    plan.setPromisedDeliveryDate(LocalDate.parse(item.getString("promisedDeliveryDate")));
+                    String dateStr = item.getString("promisedDeliveryDate");
+                    if (dateStr != null && dateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                        plan.setPromisedDeliveryDate(LocalDate.parse(dateStr));
+                    }
                 }
                 productionPlanService.save(plan);
+                createdPlans.add(plan);
                 success++;
             } catch (Exception e) {
                 log.warn("鍒涘缓鐢熶骇璁″垝澶辫触: {}", e.getMessage());
                 fail++;
             }
         }
+
+        // 鎸塸roductModelId鍒嗙粍锛岃嚜鍔ㄥ悎骞朵笅鍙�
+        Map<Long, List<ProductionPlan>> grouped = createdPlans.stream()
+                .filter(p -> p.getProductModelId() != null)
+                .collect(Collectors.groupingBy(ProductionPlan::getProductModelId));
+        for (Map.Entry<Long, List<ProductionPlan>> entry : grouped.entrySet()) {
+            try {
+                List<Long> planIds = entry.getValue().stream().map(ProductionPlan::getId).collect(Collectors.toList());
+                BigDecimal totalQty = entry.getValue().stream()
+                        .map(ProductionPlan::getQtyRequired)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add);
+                ProductionPlanDto combineDto = new ProductionPlanDto();
+                combineDto.setIds(planIds);
+                combineDto.setTotalAssignedQuantity(totalQty);
+                combineDto.setPlanCompleteTime(LocalDate.now().plusDays(ThreadLocalRandom.current().nextInt(3, 10)));
+                productionPlanService.combine(combineDto);
+                log.info("鐢熶骇璁″垝鑷姩涓嬪彂鎴愬姛, productModelId={}, 璁″垝鏁�: {}, 涓嬪彂鏁伴噺: {}",
+                        entry.getKey(), planIds.size(), totalQty);
+            } catch (Exception e) {
+                log.warn("鐢熶骇璁″垝鑷姩涓嬪彂澶辫触, productModelId={}: {}", entry.getKey(), e.getMessage());
+            }
+        }
+
         return summary("production", "鐢熶骇璁″垝", items.size(), success, fail);
     }
 
@@ -589,7 +1681,10 @@
                 order.setProductModelId(item.getLong("productModelId"));
                 order.setQuantity(item.getBigDecimal("quantity"));
                 if (item.containsKey("planCompleteTime")) {
-                    order.setPlanCompleteTime(LocalDate.parse(item.getString("planCompleteTime")));
+                    String dateStr = item.getString("planCompleteTime");
+                    if (dateStr != null && dateStr.matches("\\d{4}-\\d{2}-\\d{2}")) {
+                        order.setPlanCompleteTime(LocalDate.parse(dateStr));
+                    }
                 }
                 productionOrderService.saveProductionOrder(order);
                 success++;

--
Gitblit v1.9.3