From 4f39e676277d7a66e13d172288032ce16bb18e8c Mon Sep 17 00:00:00 2001
From: zss <zss@example.com>
Date: 星期三, 22 四月 2026 17:05:30 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_河南_鹤壁天沐钢化玻璃厂' into dev_河南_鹤壁天沐钢化玻璃厂

---
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java |  981 +++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 673 insertions(+), 308 deletions(-)

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 a740d29..c9e8734 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -18,6 +18,7 @@
 import com.ruoyi.basic.mapper.ProductModelMapper;
 import com.ruoyi.basic.pojo.Customer;
 import com.ruoyi.basic.pojo.CustomerRegions;
+import com.ruoyi.basic.pojo.Product;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.basic.service.ICustomerRegionsService;
 import com.ruoyi.common.enums.FileNameType;
@@ -87,6 +88,7 @@
 import java.nio.file.StandardCopyOption;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.time.YearMonth;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
@@ -228,11 +230,7 @@
         List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
         Map<Long, ProductModel> productModelMap = Collections.emptyMap();
         if (CollectionUtils.isNotEmpty(products)) {
-            List<Long> productModelIds = products.stream()
-                    .map(SalesLedgerProduct::getProductModelId)
-                    .filter(Objects::nonNull)
-                    .distinct()
-                    .collect(Collectors.toList());
+            List<Long> productModelIds = products.stream().map(SalesLedgerProduct::getProductModelId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
             if (CollectionUtils.isNotEmpty(productModelIds)) {
                 List<ProductModel> productModels = productModelMapper.selectBatchIds(productModelIds);
                 if (CollectionUtils.isNotEmpty(productModels)) {
@@ -248,26 +246,15 @@
             product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
             product.setRegisterDate(LocalDateTime.now());
             // 鍙戣揣淇℃伅
-            ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
-                    .eq(ShippingInfo::getSalesLedgerProductId, product.getId())
-                    .orderByDesc(ShippingInfo::getCreateTime)
-                    .last("limit 1"));
+            ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>().eq(ShippingInfo::getSalesLedgerProductId, product.getId()).orderByDesc(ShippingInfo::getCreateTime).last("limit 1"));
             if (shippingInfo != null) {
                 product.setShippingStatus(shippingInfo.getStatus());
             }
             // 鍔犲伐鏄庣粏锛屽厛鏌ind琛ㄨ幏鍙栬浜у搧鍏宠仈鐨勫伐搴忓強鏁伴噺
-            List<SalesLedgerProductProcessBind> bindList = salesLedgerProductProcessBindService.list(
-                    new LambdaQueryWrapper<SalesLedgerProductProcessBind>()
-                            .eq(SalesLedgerProductProcessBind::getSalesLedgerProductId, product.getId()));
+            List<SalesLedgerProductProcessBind> bindList = salesLedgerProductProcessBindService.list(new LambdaQueryWrapper<SalesLedgerProductProcessBind>().eq(SalesLedgerProductProcessBind::getSalesLedgerProductId, product.getId()));
             if (!bindList.isEmpty()) {
-                List<Integer> processIds = bindList.stream()
-                        .map(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId)
-                        .collect(Collectors.toList());
-                Map<Integer, Integer> processQuantityMap = bindList.stream()
-                        .collect(Collectors.toMap(
-                                SalesLedgerProductProcessBind::getSalesLedgerProductProcessId,
-                                SalesLedgerProductProcessBind::getQuantity,
-                                (a, b) -> a));
+                List<Integer> processIds = bindList.stream().map(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId).collect(Collectors.toList());
+                Map<Integer, Integer> processQuantityMap = bindList.stream().collect(Collectors.toMap(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId, SalesLedgerProductProcessBind::getQuantity, (a, b) -> a));
                 List<SalesLedgerProductProcess> processList = salesLedgerProductProcessService.listByIds(processIds);
                 processList.forEach(p -> p.setQuantity(processQuantityMap.get(p.getId())));
                 product.setSalesProductProcessList(processList);
@@ -291,8 +278,7 @@
 
         // 3.鏌ヨ涓婁紶鏂囦欢
         LambdaQueryWrapper<CommonFile> salesLedgerFileWrapper = new LambdaQueryWrapper<>();
-        salesLedgerFileWrapper.eq(CommonFile::getCommonId, salesLedger.getId())
-                .eq(CommonFile::getType, FileNameType.SALE.getValue());
+        salesLedgerFileWrapper.eq(CommonFile::getCommonId, salesLedger.getId()).eq(CommonFile::getType, FileNameType.SALE.getValue());
         List<CommonFile> salesLedgerFiles = commonFileMapper.selectList(salesLedgerFileWrapper);
 
         // 4. 杞崲 DTO
@@ -315,11 +301,7 @@
         List<Map<String, Object>> result = salesLedgerMapper.selectMaps(queryWrapper);
 
         // 灏嗕笅鍒掔嚎鍛藉悕杞崲涓洪┘宄板懡鍚�
-        return result.stream().map(map -> map.entrySet().stream()
-                .collect(Collectors.toMap(
-                        entry -> underlineToCamel(entry.getKey()),
-                        Map.Entry::getValue))
-        ).collect(Collectors.toList());
+        return result.stream().map(map -> map.entrySet().stream().collect(Collectors.toMap(entry -> underlineToCamel(entry.getKey()), Map.Entry::getValue))).collect(Collectors.toList());
     }
 
     @Override
@@ -335,10 +317,7 @@
         // 鎵ц鏌ヨ骞惰绠楁�诲拰
         List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(queryWrapper);
 
-        BigDecimal totalContractAmount = salesLedgers.stream()
-                .map(SalesLedger::getContractAmount)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        BigDecimal totalContractAmount = salesLedgers.stream().map(SalesLedger::getContractAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
 
         return totalContractAmount;
     }
@@ -347,32 +326,23 @@
     public List getTopFiveList() {
         // 鏌ヨ鍘熷鏁版嵁
         LambdaQueryWrapper<SalesLedger> queryWrapper = Wrappers.lambdaQuery();
-        queryWrapper.select(SalesLedger::getCustomerId,
-                        SalesLedger::getCustomerName,
-                        SalesLedger::getContractAmount)
-                .orderByDesc(SalesLedger::getContractAmount);
+        queryWrapper.select(SalesLedger::getCustomerId, SalesLedger::getCustomerName, SalesLedger::getContractAmount).orderByDesc(SalesLedger::getContractAmount);
         List<SalesLedger> records = salesLedgerMapper.selectList(queryWrapper);
 
         // 鎸夊鎴稩D鍒嗙粍骞惰仛鍚堥噾棰�
         Map<Long, GroupedCustomer> groupedMap = new LinkedHashMap<>(); // 浣跨敤LinkedHashMap淇濇寔鎺掑簭
         for (SalesLedger record : records) {
-            groupedMap.computeIfAbsent(record.getCustomerId(),
-                            k -> new GroupedCustomer(record.getCustomerId(), record.getCustomerName()))
-                    .addAmount(record.getContractAmount());
+            groupedMap.computeIfAbsent(record.getCustomerId(), k -> new GroupedCustomer(record.getCustomerId(), record.getCustomerName())).addAmount(record.getContractAmount());
         }
 
         // 杞崲涓虹粨鏋滃垪琛ㄥ苟鍙栧墠5
-        return groupedMap.values().stream()
-                .sorted(Comparator.comparing(GroupedCustomer::getTotalAmount).reversed())
-                .limit(5)
-                .map(customer -> {
-                    Map<String, Object> result = new HashMap<>();
-                    result.put("customerId", customer.getCustomerId());
-                    result.put("customerName", customer.getCustomerName());
-                    result.put("totalAmount", customer.getTotalAmount());
-                    return result;
-                })
-                .collect(Collectors.toList());
+        return groupedMap.values().stream().sorted(Comparator.comparing(GroupedCustomer::getTotalAmount).reversed()).limit(5).map(customer -> {
+            Map<String, Object> result = new HashMap<>();
+            result.put("customerId", customer.getCustomerId());
+            result.put("customerName", customer.getCustomerName());
+            result.put("totalAmount", customer.getTotalAmount());
+            return result;
+        }).collect(Collectors.toList());
     }
 
     @Override
@@ -388,31 +358,19 @@
 
             //  鍥炴閲戦
             LambdaQueryWrapper<ReceiptPayment> receiptPaymentQuery = new LambdaQueryWrapper<>();
-            receiptPaymentQuery
-                    .ge(ReceiptPayment::getCreateTime, startTime)
-                    .le(ReceiptPayment::getCreateTime, endTime);
+            receiptPaymentQuery.ge(ReceiptPayment::getCreateTime, startTime).le(ReceiptPayment::getCreateTime, endTime);
 
-            List<ReceiptPayment> receiptPayments =
-                    receiptPaymentMapper.selectList(receiptPaymentQuery);
+            List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(receiptPaymentQuery);
 
-            BigDecimal receiptAmount = receiptPayments.stream()
-                    .map(ReceiptPayment::getReceiptPaymentAmount)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal receiptAmount = receiptPayments.stream().map(ReceiptPayment::getReceiptPaymentAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
 
             //  寮�绁ㄩ噾棰�
             LambdaQueryWrapper<InvoiceLedger> invoiceLedgerQuery = new LambdaQueryWrapper<>();
-            invoiceLedgerQuery
-                    .ge(InvoiceLedger::getCreateTime, startTime)
-                    .le(InvoiceLedger::getCreateTime, endTime);
+            invoiceLedgerQuery.ge(InvoiceLedger::getCreateTime, startTime).le(InvoiceLedger::getCreateTime, endTime);
 
-            List<InvoiceLedger> invoiceLedgers =
-                    invoiceLedgerMapper.selectList(invoiceLedgerQuery);
+            List<InvoiceLedger> invoiceLedgers = invoiceLedgerMapper.selectList(invoiceLedgerQuery);
 
-            BigDecimal invoiceAmount = invoiceLedgers.stream()
-                    .map(InvoiceLedger::getInvoiceTotal)
-                    .filter(Objects::nonNull)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal invoiceAmount = invoiceLedgers.stream().map(InvoiceLedger::getInvoiceTotal).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
 
             MonthlyAmountDto dto = new MonthlyAmountDto();
             dto.setMonth(yearMonth.format(DateTimeFormatter.ofPattern("yyyy-MM")));
@@ -438,9 +396,7 @@
         boolean hasWidthHeightFilter = salesLedgerDto.getWidth() != null || salesLedgerDto.getHeight() != null;
         Map<Long, List<SalesLedgerProduct>> matchedProductsMap = Collections.emptyMap();
         if (hasWidthHeightFilter) {
-            LambdaQueryWrapper<SalesLedgerProduct> productQueryWrapper = new LambdaQueryWrapper<SalesLedgerProduct>()
-                    .in(SalesLedgerProduct::getSalesLedgerId, salesLedgerIds)
-                    .eq(SalesLedgerProduct::getType, 1);
+            LambdaQueryWrapper<SalesLedgerProduct> productQueryWrapper = new LambdaQueryWrapper<SalesLedgerProduct>().in(SalesLedgerProduct::getSalesLedgerId, salesLedgerIds).eq(SalesLedgerProduct::getType, 1);
             if (salesLedgerDto.getWidth() != null) {
                 productQueryWrapper.eq(SalesLedgerProduct::getWidth, salesLedgerDto.getWidth());
             }
@@ -448,34 +404,22 @@
                 productQueryWrapper.eq(SalesLedgerProduct::getHeight, salesLedgerDto.getHeight());
             }
             List<SalesLedgerProduct> matchedProducts = salesLedgerProductMapper.selectList(productQueryWrapper);
-            matchedProductsMap = CollectionUtils.isEmpty(matchedProducts) ? Collections.emptyMap()
-                    : matchedProducts.stream().collect(Collectors.groupingBy(SalesLedgerProduct::getSalesLedgerId));
+            matchedProductsMap = CollectionUtils.isEmpty(matchedProducts) ? Collections.emptyMap() : matchedProducts.stream().collect(Collectors.groupingBy(SalesLedgerProduct::getSalesLedgerId));
         }
 
         List<SalesLedgerProductTotalsDto> productTotals = salesLedgerProductMapper.selectSalesLedgerProductTotals(salesLedgerIds, 1);
-        Map<Long, SalesLedgerProductTotalsDto> productTotalsMap = CollectionUtils.isEmpty(productTotals)
-                ? Collections.emptyMap()
-                : productTotals.stream()
-                .filter(t -> t.getSalesLedgerId() != null)
-                .collect(Collectors.toMap(SalesLedgerProductTotalsDto::getSalesLedgerId, Function.identity(), (a, b) -> a));
+        Map<Long, SalesLedgerProductTotalsDto> productTotalsMap = CollectionUtils.isEmpty(productTotals) ? Collections.emptyMap() : productTotals.stream().filter(t -> t.getSalesLedgerId() != null).collect(Collectors.toMap(SalesLedgerProductTotalsDto::getSalesLedgerId, Function.identity(), (a, b) -> a));
 
         List<InvoiceLedgerDto> invoiceLedgerDtoList = invoiceLedgerMapper.invoicedTotal(salesLedgerIds);
         if (CollectionUtils.isEmpty(invoiceLedgerDtoList)) {
             invoiceLedgerDtoList = Collections.emptyList();
         }
 
-        Map<Long, BigDecimal> invoiceTotals = invoiceLedgerDtoList.stream()
-                .filter(dto -> dto.getSalesLedgerId() != null && dto.getInvoiceTotal() != null)
-                .collect(Collectors.toMap(
-                        dto -> dto.getSalesLedgerId().longValue(),
-                        InvoiceLedgerDto::getInvoiceTotal,
-                        BigDecimal::add
-                ));
+        Map<Long, BigDecimal> invoiceTotals = invoiceLedgerDtoList.stream().filter(dto -> dto.getSalesLedgerId() != null && dto.getInvoiceTotal() != null).collect(Collectors.toMap(dto -> dto.getSalesLedgerId().longValue(), InvoiceLedgerDto::getInvoiceTotal, BigDecimal::add));
 
         List<ReceiptPayment> receiptPayments = Collections.emptyList();
         if (!CollectionUtils.isEmpty(salesLedgerIds)) {
-            receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>()
-                    .in(ReceiptPayment::getSalesLedgerId, salesLedgerIds));
+            receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>().in(ReceiptPayment::getSalesLedgerId, salesLedgerIds));
         }
 
         Map<Long, BigDecimal> receiptTotals = new HashMap<>();
@@ -527,8 +471,7 @@
         }
 
         if (salesLedgerDto.getStatus() != null && salesLedgerDto.getStatus()) {
-            iPage.getRecords().removeIf(salesLedger ->
-                    Objects.equals(salesLedger.getNoInvoiceAmountTotal(), new BigDecimal("0.00")));
+            iPage.getRecords().removeIf(salesLedger -> Objects.equals(salesLedger.getNoInvoiceAmountTotal(), new BigDecimal("0.00")));
             iPage.setTotal(iPage.getRecords().size());
         }
 
@@ -565,16 +508,12 @@
             throw new ServiceException("瀵煎叆澶辫触,閿�鍞骇鍝佹暟鎹负绌�");
         }
         // 瀹㈡埛鏁版嵁
-        List<Customer> customers = customerMapper.selectList(new LambdaQueryWrapper<Customer>().in(Customer::getCustomerName,
-                salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getCustomerName).collect(Collectors.toList())));
+        List<Customer> customers = customerMapper.selectList(new LambdaQueryWrapper<Customer>().in(Customer::getCustomerName, salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getCustomerName).collect(Collectors.toList())));
         List<Map<String, Object>> list = productModelMapper.getProductAndModelList();
         // 褰曞叆浜烘暟鎹�
-        List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName,
-                salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getEntryPerson).collect(Collectors.toList())));
+        List<SysUser> sysUsers = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getNickName, salesLedgerImportDtoList.stream().map(SalesLedgerImportDto::getEntryPerson).collect(Collectors.toList())));
         for (SalesLedgerImportDto salesLedgerImportDto : salesLedgerImportDtoList) {
-            SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>()
-                    .eq(SalesLedger::getSalesContractNo, salesLedgerImportDto.getSalesContractNo())
-                    .last("LIMIT 1"));
+            SalesLedger salesLedger1 = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>().eq(SalesLedger::getSalesContractNo, salesLedgerImportDto.getSalesContractNo()).last("LIMIT 1"));
             if (salesLedger1 != null) {
                 throw new ServiceException("瀵煎叆澶辫触锛氬悎鍚屽彿 [" + salesLedgerImportDto.getSalesContractNo() + "] 宸插瓨鍦紝璇锋鏌ュ悗閲嶆柊瀵煎叆");
             }
@@ -590,35 +529,19 @@
             salesLedger.setExecutionDate(DateUtils.toLocalDate(salesLedgerImportDto.getExecutionDate()));
 
             LocalDate expectedDeliveryDate = DateUtils.toLocalDate(salesLedgerImportDto.getEntryDate()).plusDays(7);
-            LocalDate importDeliveryDate = salesLedgerImportDto.getDeliveryDate() == null
-                    ? null
-                    : DateUtils.toLocalDate(salesLedgerImportDto.getDeliveryDate());
+            LocalDate importDeliveryDate = salesLedgerImportDto.getDeliveryDate() == null ? null : DateUtils.toLocalDate(salesLedgerImportDto.getDeliveryDate());
             // 浜や粯鏃ユ湡涓虹┖鍒欓粯璁ゅ彇褰曞叆鏃ユ湡鍚�7澶�
             salesLedger.setDeliveryDate(importDeliveryDate == null ? expectedDeliveryDate : importDeliveryDate);
             // 閫氳繃瀹㈡埛鍚嶇О鏌ヨ瀹㈡埛ID锛屽鎴峰悎鍚屽彿
-            salesLedger.setCustomerId(customers.stream()
-                    .filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName()))
-                    .findFirst()
-                    .map(Customer::getId)
-                    .orElse(null));
-            salesLedger.setCustomerContractNo(customers.stream()
-                    .filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName()))
-                    .findFirst()
-                    .map(Customer::getTaxpayerIdentificationNumber)
-                    .orElse(null));
-            Long aLong = sysUsers.stream()
-                    .filter(sysUser -> sysUser.getNickName().equals(salesLedger.getEntryPerson()))
-                    .findFirst()
-                    .map(SysUser::getUserId)
-                    .orElse(null);
+            salesLedger.setCustomerId(customers.stream().filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName())).findFirst().map(Customer::getId).orElse(null));
+            salesLedger.setCustomerContractNo(customers.stream().filter(customer -> customer.getCustomerName().equals(salesLedger.getCustomerName())).findFirst().map(Customer::getTaxpayerIdentificationNumber).orElse(null));
+            Long aLong = sysUsers.stream().filter(sysUser -> sysUser.getNickName().equals(salesLedger.getEntryPerson())).findFirst().map(SysUser::getUserId).orElse(null);
             if (aLong == null) {
                 throw new ServiceException("褰曞叆浜�:" + salesLedger.getEntryPerson() + ",鏃犲搴旂敤鎴凤紒");
             }
             salesLedger.setEntryPerson(aLong.toString());
             // 閿�鍞骇鍝佹暟鎹粦瀹氾紝閫氳繃閿�鍞崟鍙疯幏鍙栧搴旈攢鍞骇鍝佹暟鎹�
-            List<SalesLedgerProductImportDto> salesLedgerProductImportDtos = salesLedgerProductImportDtoList.stream()
-                    .filter(salesLedgerProductImportDto -> salesLedgerProductImportDto.getSalesContractNo().equals(salesLedger.getSalesContractNo()))
-                    .collect(Collectors.toList());
+            List<SalesLedgerProductImportDto> salesLedgerProductImportDtos = salesLedgerProductImportDtoList.stream().filter(salesLedgerProductImportDto -> salesLedgerProductImportDto.getSalesContractNo().equals(salesLedger.getSalesContractNo())).collect(Collectors.toList());
             if (CollectionUtils.isEmpty(salesLedgerProductImportDtos)) {
                 throw new ServiceException("閿�鍞崟鍙�:" + salesLedgerImportDto.getSalesContractNo() + ",鏃犲搴斾骇鍝佹暟鎹紒");
             }
@@ -659,30 +582,21 @@
                 salesLedgerProduct.setActualPieceArea(actualPieceArea);
                 salesLedgerProduct.setActualTotalArea(actualPieceArea.multiply(quantity).setScale(4, RoundingMode.HALF_UP));
 
-                BigDecimal settlePieceArea = salesLedgerProduct.getSettlePieceArea() == null
-                        ? actualPieceArea
-                        : salesLedgerProduct.getSettlePieceArea();
+                BigDecimal settlePieceArea = salesLedgerProduct.getSettlePieceArea() == null ? actualPieceArea : salesLedgerProduct.getSettlePieceArea();
                 salesLedgerProduct.setSettlePieceArea(settlePieceArea);
                 salesLedgerProduct.setSettleTotalArea(settlePieceArea.multiply(quantity).setScale(4, RoundingMode.HALF_UP));
 
                 BigDecimal perimeter = BigDecimal.ZERO;
                 if (width.compareTo(BigDecimal.ZERO) > 0 && height.compareTo(BigDecimal.ZERO) > 0) {
-                    perimeter = width.add(height)
-                            .multiply(new BigDecimal("2"))
-                            .divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
+                    perimeter = width.add(height).multiply(new BigDecimal("2")).divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
                 }
                 salesLedgerProduct.setPerimeter(perimeter);
 
                 BigDecimal extraProcessAmountPerPiece = BigDecimal.ZERO;
-                list.stream()
-                        .filter(Objects::nonNull)
-                        .filter(map -> Objects.equals(Objects.toString(map.get("productName"), null), salesLedgerProduct.getProductCategory())
-                                && Objects.equals(Objects.toString(map.get("model"), null), salesLedgerProduct.getSpecificationModel()))
-                        .findFirst()
-                        .ifPresent(map -> {
-                            salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString()));
-                            salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString()));
-                        });
+                list.stream().filter(Objects::nonNull).filter(map -> Objects.equals(Objects.toString(map.get("productName"), null), salesLedgerProduct.getProductCategory()) && Objects.equals(Objects.toString(map.get("model"), null), salesLedgerProduct.getSpecificationModel())).findFirst().ifPresent(map -> {
+                    salesLedgerProduct.setProductModelId(Long.parseLong(map.get("modelId").toString()));
+                    salesLedgerProduct.setProductId(Long.parseLong(map.get("id").toString()));
+                });
                 salesLedgerProduct.setRegister(loginUser.getNickName());
                 salesLedgerProduct.setRegisterDate(LocalDateTime.now());
                 salesLedgerProduct.setApproveStatus(0);
@@ -702,19 +616,13 @@
                                 String qtyStr = parts[1].trim();
                                 try {
                                     BigDecimal processQty = new BigDecimal(qtyStr);
-                                    SalesLedgerProductProcess process = salesLedgerProductProcessService.getOne(
-                                            new LambdaQueryWrapper<SalesLedgerProductProcess>()
-                                                    .eq(SalesLedgerProductProcess::getProcessName, processName)
-                                                    .last("LIMIT 1")
-                                    );
+                                    SalesLedgerProductProcess process = salesLedgerProductProcessService.getOne(new LambdaQueryWrapper<SalesLedgerProductProcess>().eq(SalesLedgerProductProcess::getProcessName, processName).last("LIMIT 1"));
                                     if (process != null) {
                                         SalesLedgerProductProcess p = new SalesLedgerProductProcess();
                                         p.setId(process.getId());
                                         p.setQuantity(processQty.intValue());
                                         processList.add(p);
-                                        extraProcessAmountPerPiece = extraProcessAmountPerPiece.add(
-                                                defaultDecimal(process.getUnitPrice()).multiply(processQty)
-                                        );
+                                        extraProcessAmountPerPiece = extraProcessAmountPerPiece.add(defaultDecimal(process.getUnitPrice()).multiply(processQty));
                                     }
                                 } catch (Exception e) {
                                     log.error("瑙f瀽棰濆鍔犲伐鏁伴噺澶辫触: {}", qtyStr);
@@ -725,18 +633,13 @@
                 }
 
                 // 鍚◣鎬讳环 = 鍗曚环 * 缁撶畻闈㈢Н * 鏁伴噺 + 棰濆鍔犲伐閲戦 * 鏁伴噺
-                BigDecimal taxInclusiveTotalPrice = unitPrice.multiply(settlePieceArea)
-                        .multiply(quantity)
-                        .add(extraProcessAmountPerPiece.multiply(quantity))
-                        .setScale(2, RoundingMode.HALF_UP);
+                BigDecimal taxInclusiveTotalPrice = unitPrice.multiply(settlePieceArea).multiply(quantity).add(extraProcessAmountPerPiece.multiply(quantity)).setScale(2, RoundingMode.HALF_UP);
                 salesLedgerProduct.setTaxInclusiveTotalPrice(taxInclusiveTotalPrice);
                 assertPositive(taxInclusiveTotalPrice, "鍚◣鎬讳环", locate);
 
                 // 绋庣巼鍏佽涓虹┖锛岀┖鍊兼寜0澶勭悊
                 BigDecimal taxDivisor = BigDecimal.ONE.add(taxRate.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP));
-                salesLedgerProduct.setTaxExclusiveTotalPrice(
-                        taxInclusiveTotalPrice.divide(taxDivisor, 2, RoundingMode.HALF_UP)
-                );
+                salesLedgerProduct.setTaxExclusiveTotalPrice(taxInclusiveTotalPrice.divide(taxDivisor, 2, RoundingMode.HALF_UP));
                 salesLedgerProduct.setNoInvoiceNum(quantity);
                 salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxExclusiveTotalPrice());
                 salesLedgerProduct.setPendingInvoiceTotal(taxInclusiveTotalPrice);
@@ -809,10 +712,7 @@
                 product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName());
                 product.setRegisterDate(LocalDateTime.now());
                 // 鍙戣揣淇℃伅
-                ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>()
-                        .eq(ShippingInfo::getSalesLedgerProductId, product.getId())
-                        .orderByDesc(ShippingInfo::getCreateTime)
-                        .last("limit 1"));
+                ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>().eq(ShippingInfo::getSalesLedgerProductId, product.getId()).orderByDesc(ShippingInfo::getCreateTime).last("limit 1"));
                 product.setShippingCarNumber(shippingInfo.getShippingCarNumber());
                 product.setShippingDate(shippingInfo.getShippingDate());
                 if (shippingInfo != null) {
@@ -889,21 +789,16 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int deleteSalesLedgerByIds(Long[] ids) {
-        List<Long> idList = Arrays.stream(ids)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList());
+        List<Long> idList = Arrays.stream(ids).filter(Objects::nonNull).collect(Collectors.toList());
         if (CollectionUtils.isEmpty(idList)) {
             return 0;
         }
         // 鍒犻櫎閿�鍞鐞嗘暟鎹�
         LambdaQueryWrapper<SalesLedgerProduct> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, idList)
-                .select(SalesLedgerProduct::getId);
+        queryWrapper.in(SalesLedgerProduct::getSalesLedgerId, idList).select(SalesLedgerProduct::getId);
 
         List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(queryWrapper);
-        List<Long> productIds = products.stream()
-                .map(SalesLedgerProduct::getId)
-                .collect(Collectors.toList());
+        List<Long> productIds = products.stream().map(SalesLedgerProduct::getId).collect(Collectors.toList());
         //鍒犻櫎鐢熶骇鏁版嵁
         salesLedgerProductServiceImpl.deleteProductionData(productIds);
 
@@ -939,27 +834,16 @@
             receiptPaymentMapper.delete(wrapperTree);
         }
         // 鍒犻櫎鍙戣揣鍙拌处璁板綍
-        List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
-                .in(ShippingInfo::getSalesLedgerId, idList));
+        List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>().in(ShippingInfo::getSalesLedgerId, idList));
         if (CollectionUtils.isNotEmpty(shippingInfos)) {
             shippingInfoServiceImpl.delete(shippingInfos.stream().map(ShippingInfo::getId).collect(Collectors.toList()));
         }
         // 鍒犻櫎鍏宠仈鐨勫叆搴�/鍑哄簱璁板綍锛堣蛋鏈嶅姟灞傚垹闄わ紝瑙﹀彂搴撳瓨鏁伴噺鍥為��锛�
-        List<Long> stockInRecordIds = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>()
-                        .in(StockInRecord::getSalesLedgerId, idList)
-                        .select(StockInRecord::getId))
-                .stream()
-                .map(StockInRecord::getId)
-                .collect(Collectors.toList());
+        List<Long> stockInRecordIds = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>().in(StockInRecord::getSalesLedgerId, idList).select(StockInRecord::getId)).stream().map(StockInRecord::getId).collect(Collectors.toList());
         if (CollectionUtils.isNotEmpty(stockInRecordIds)) {
             stockInRecordService.batchDelete(stockInRecordIds);
         }
-        List<Long> stockOutRecordIds = stockOutRecordMapper.selectList(new LambdaQueryWrapper<StockOutRecord>()
-                        .in(StockOutRecord::getSalesLedgerId, idList)
-                        .select(StockOutRecord::getId))
-                .stream()
-                .map(StockOutRecord::getId)
-                .collect(Collectors.toList());
+        List<Long> stockOutRecordIds = stockOutRecordMapper.selectList(new LambdaQueryWrapper<StockOutRecord>().in(StockOutRecord::getSalesLedgerId, idList).select(StockOutRecord::getId)).stream().map(StockOutRecord::getId).collect(Collectors.toList());
         if (CollectionUtils.isNotEmpty(stockOutRecordIds)) {
             stockOutRecordService.batchDelete(stockOutRecordIds);
         }
@@ -1010,13 +894,7 @@
             List<SalesLedgerProduct> productList = salesLedgerDto.getProductData();
             if (productList != null && !productList.isEmpty()) {
                 handleSalesLedgerProducts(salesLedger.getId(), productList, EnumUtil.fromCode(SaleEnum.class, salesLedgerDto.getType()));
-                updateMainContractAmount(
-                        salesLedger.getId(),
-                        productList,
-                        SalesLedgerProduct::getTaxInclusiveTotalPrice,
-                        salesLedgerMapper,
-                        SalesLedger.class
-                );
+                updateMainContractAmount(salesLedger.getId(), productList, SalesLedgerProduct::getTaxInclusiveTotalPrice, salesLedgerMapper, SalesLedger.class);
             }
 
             // 5. 杩佺Щ涓存椂鏂囦欢鍒版寮忕洰褰�
@@ -1062,10 +940,7 @@
             // 鏋勫缓姝e紡鏂囦欢鍚嶏紙鍖呭惈涓氬姟ID鍜屾椂闂存埑锛岄伩鍏嶅啿绐侊級
             String originalFilename = tempFile.getOriginalName();
             String fileExtension = FilenameUtils.getExtension(originalFilename);
-            String formalFilename = businessId + "_" +
-                    System.currentTimeMillis() + "_" +
-                    UUID.randomUUID().toString().substring(0, 8) +
-                    (StringUtils.hasText(fileExtension) ? "." + fileExtension : "");
+            String formalFilename = businessId + "_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8) + (StringUtils.hasText(fileExtension) ? "." + fileExtension : "");
 
             Path formalFilePath = formalDirPath.resolve(formalFilename);
 
@@ -1109,9 +984,7 @@
     @Override
     public void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, SaleEnum type) {
         // 鎸塈D鍒嗙粍锛屽尯鍒嗘柊澧炲拰鏇存柊鐨勮褰�
-        Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream()
-                .peek(p -> p.setSalesLedgerId(salesLedgerId))
-                .collect(Collectors.partitioningBy(p -> p.getId() != null));
+        Map<Boolean, List<SalesLedgerProduct>> partitionedProducts = products.stream().peek(p -> p.setSalesLedgerId(salesLedgerId)).collect(Collectors.partitioningBy(p -> p.getId() != null));
 
         List<SalesLedgerProduct> updateList = partitionedProducts.get(true);
         List<SalesLedgerProduct> insertList = partitionedProducts.get(false);
@@ -1178,10 +1051,7 @@
         if (salesLedgerId == null) return;
         SalesLedger ledger = baseMapper.selectById(salesLedgerId);
         if (ledger == null) return;
-        List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList(
-                Wrappers.<SalesLedgerProduct>lambdaQuery()
-                        .eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)
-                        .eq(SalesLedgerProduct::getType, SaleEnum.SALE.getCode()));
+        List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId).eq(SalesLedgerProduct::getType, SaleEnum.SALE.getCode()));
         if (CollectionUtils.isEmpty(allProducts)) {
             ledger.setStockStatus(0);
             baseMapper.updateById(ledger);
@@ -1248,11 +1118,7 @@
         } finally {
             // 3. 閲婃斁閿�
             String luaScript = "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end";
-            redisTemplate.execute(
-                    new DefaultRedisScript<>(luaScript, Long.class),
-                    Collections.singletonList(lockKey),
-                    lockValue
-            );
+            redisTemplate.execute(new DefaultRedisScript<>(luaScript, Long.class), Collections.singletonList(lockKey), lockValue);
         }
     }
 
@@ -1309,8 +1175,7 @@
         dto.setOrderProcessRequirement(salesLedger.getRemarks());
 
         //  鏌ヨ浜у搧鍒楄〃
-        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(
-                new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId));
+        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId));
 
         BigDecimal totalQuantity = BigDecimal.ZERO;
         BigDecimal totalArea = BigDecimal.ZERO;
@@ -1320,8 +1185,7 @@
             SalesProcessCardDto.ProcessCardItemDto itemDto = new SalesProcessCardDto.ProcessCardItemDto();
             itemDto.setFloorCode(p.getFloorCode());
             // 缁勮浜у搧鎻忚堪锛氬ぇ绫� + (瑙勬牸)
-            String desc = (p.getProductCategory() != null ? p.getProductCategory() : "") +
-                    (StringUtils.isNotBlank(p.getSpecificationModel()) ? " " + p.getSpecificationModel() : "");
+            String desc = (p.getProductCategory() != null ? p.getProductCategory() : "") + (StringUtils.isNotBlank(p.getSpecificationModel()) ? " " + p.getSpecificationModel() : "");
             itemDto.setProductDescription(desc.trim());
             itemDto.setWidth(p.getWidth());
             itemDto.setHeight(p.getHeight());
@@ -1348,28 +1212,18 @@
         dto.setTotalArea(totalArea.setScale(2, RoundingMode.HALF_UP));
 
         //  宸ヨ壓璺嚎
-        List<SalesLedgerProcessRoute> salesLedgerProcessRoutes = salesLedgerProcessRouteService.list(
-                new LambdaQueryWrapper<SalesLedgerProcessRoute>()
-                        .eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedgerId)
-                        .orderByAsc(SalesLedgerProcessRoute::getDragSort));
+        List<SalesLedgerProcessRoute> salesLedgerProcessRoutes = salesLedgerProcessRouteService.list(new LambdaQueryWrapper<SalesLedgerProcessRoute>().eq(SalesLedgerProcessRoute::getSalesLedgerId, salesLedgerId).orderByAsc(SalesLedgerProcessRoute::getDragSort));
 
         List<SalesProcessCardDto.ProcessNodeDto> nodeDtos = new ArrayList<>();
 
         if (CollectionUtils.isEmpty(salesLedgerProcessRoutes)) {
             // 鏃犺嚜瀹氫箟璺嚎锛氬厛鏌ヨ榛樿宸ヨ壓璺嚎锛涜嫢鏃犻粯璁わ紝鑾峰彇鍒涘缓鏃堕棿鏈�杩戠殑涓�鏉�
-            ProcessRoute fallbackRoute = processRouteMapper.selectOne(
-                    new LambdaQueryWrapper<ProcessRoute>().eq(ProcessRoute::getIsDefault, 1).last("LIMIT 1"));
+            ProcessRoute fallbackRoute = processRouteMapper.selectOne(new LambdaQueryWrapper<ProcessRoute>().eq(ProcessRoute::getIsDefault, 1).last("LIMIT 1"));
             if (fallbackRoute == null) {
-                fallbackRoute = processRouteMapper.selectOne(
-                        new LambdaQueryWrapper<ProcessRoute>()
-                                .orderByDesc(ProcessRoute::getCreateTime)
-                                .last("LIMIT 1"));
+                fallbackRoute = processRouteMapper.selectOne(new LambdaQueryWrapper<ProcessRoute>().orderByDesc(ProcessRoute::getCreateTime).last("LIMIT 1"));
             }
             if (fallbackRoute != null) {
-                List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList(
-                        new LambdaQueryWrapper<ProcessRouteItem>()
-                                .eq(ProcessRouteItem::getRouteId, fallbackRoute.getId())
-                                .orderByAsc(ProcessRouteItem::getDragSort));
+                List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList(new LambdaQueryWrapper<ProcessRouteItem>().eq(ProcessRouteItem::getRouteId, fallbackRoute.getId()).orderByAsc(ProcessRouteItem::getDragSort));
                 for (ProcessRouteItem i : routeItems) {
                     SalesProcessCardDto.ProcessNodeDto node = new SalesProcessCardDto.ProcessNodeDto();
                     node.setProcessRouteItemId(i.getId());
@@ -1380,12 +1234,9 @@
             }
         } else {
             // 浣跨敤鑷畾涔夎矾绾跨粦瀹氱殑鑺傜偣
-            List<Long> itemIds = salesLedgerProcessRoutes.stream()
-                    .map(SalesLedgerProcessRoute::getProcessRouteItemId)
-                    .collect(Collectors.toList());
+            List<Long> itemIds = salesLedgerProcessRoutes.stream().map(SalesLedgerProcessRoute::getProcessRouteItemId).collect(Collectors.toList());
             List<ProcessRouteItem> rawItems = processRouteItemMapper.selectBatchIds(itemIds);
-            Map<Long, ProcessRouteItem> itemMap = rawItems.stream()
-                    .collect(Collectors.toMap(ProcessRouteItem::getId, i -> i, (a, b) -> a));
+            Map<Long, ProcessRouteItem> itemMap = rawItems.stream().collect(Collectors.toMap(ProcessRouteItem::getId, i -> i, (a, b) -> a));
 
             for (SalesLedgerProcessRoute r : salesLedgerProcessRoutes) {
                 ProcessRouteItem pi = itemMap.get(r.getProcessRouteItemId());
@@ -1402,14 +1253,9 @@
 
         if (!nodeDtos.isEmpty()) {
             //  dragSort 杩涜鍗囧簭鎺掑簭
-            nodeDtos.sort(Comparator.comparing(
-                    SalesProcessCardDto.ProcessNodeDto::getDragSort,
-                    Comparator.nullsLast(Comparator.naturalOrder())
-            ));
+            nodeDtos.sort(Comparator.comparing(SalesProcessCardDto.ProcessNodeDto::getDragSort, Comparator.nullsLast(Comparator.naturalOrder())));
             //  閲嶆柊鐢熸垚鎺掑簭鍚庣殑璺緞鍚嶇О鍒楄〃
-            List<String> sortedPathNames = nodeDtos.stream()
-                    .map(SalesProcessCardDto.ProcessNodeDto::getProcessRouteItemName)
-                    .collect(Collectors.toList());
+            List<String> sortedPathNames = nodeDtos.stream().map(SalesProcessCardDto.ProcessNodeDto::getProcessRouteItemName).collect(Collectors.toList());
             //  鎷兼帴瀛楃涓�
             dto.setProcessPathDisplay(String.join(" -> ", sortedPathNames));
             // 璁剧疆椤跺眰鑺傜偣鐨勫伐鑹鸿矾绾�
@@ -1479,8 +1325,7 @@
         dto.setPrintTime(LocalDateTime.now());
 
         // 鏌ヨ浜у搧鍒楄〃
-        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(
-                new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId));
+        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId));
 
         if (CollectionUtils.isNotEmpty(products)) {
             SalesLedgerProduct firstProduct = products.get(0);
@@ -1495,8 +1340,7 @@
         for (SalesLedgerProduct p : products) {
             SalesOrdersDto.SalesOrderItemDto itemDto = new SalesOrdersDto.SalesOrderItemDto();
             itemDto.setFloorCode(p.getFloorCode());
-            String desc = (p.getProductCategory() != null ? p.getProductCategory() : "") +
-                    (StringUtils.isNotBlank(p.getSpecificationModel()) ? " " + p.getSpecificationModel() : "");
+            String desc = (p.getProductCategory() != null ? p.getProductCategory() : "") + (StringUtils.isNotBlank(p.getSpecificationModel()) ? " " + p.getSpecificationModel() : "");
             itemDto.setProductDescription(desc.trim());
             itemDto.setWidth(p.getWidth());
             itemDto.setHeight(p.getHeight());
@@ -1528,13 +1372,10 @@
         List<Long> productIds = products.stream().map(SalesLedgerProduct::getId).collect(Collectors.toList());
         BigDecimal otherFeesTotal = BigDecimal.ZERO;
         if (CollectionUtils.isNotEmpty(productIds)) {
-            List<SalesLedgerProductProcessBind> binds = salesLedgerProductProcessBindService.list(
-                    new LambdaQueryWrapper<SalesLedgerProductProcessBind>().in(SalesLedgerProductProcessBind::getSalesLedgerProductId, productIds));
+            List<SalesLedgerProductProcessBind> binds = salesLedgerProductProcessBindService.list(new LambdaQueryWrapper<SalesLedgerProductProcessBind>().in(SalesLedgerProductProcessBind::getSalesLedgerProductId, productIds));
 
             if (CollectionUtils.isNotEmpty(binds)) {
-                Map<Integer, Integer> processQuantityMap = binds.stream()
-                        .collect(Collectors.groupingBy(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId,
-                                Collectors.summingInt(b -> b.getQuantity() != null ? b.getQuantity() : 0)));
+                Map<Integer, Integer> processQuantityMap = binds.stream().collect(Collectors.groupingBy(SalesLedgerProductProcessBind::getSalesLedgerProductProcessId, Collectors.summingInt(b -> b.getQuantity() != null ? b.getQuantity() : 0)));
 
                 List<Integer> processIds = new ArrayList<>(processQuantityMap.keySet());
                 List<SalesLedgerProductProcess> processes = salesLedgerProductProcessService.listByIds(processIds);
@@ -1616,14 +1457,10 @@
 //        dto.setExternalOrderNo(ledgers.get(0).getCustomerContractNo());
 
         //  鏌ヨ鎵�鏈変骇鍝�
-        List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList(
-                new LambdaQueryWrapper<SalesLedgerProduct>()
-                        .in(SalesLedgerProduct::getSalesLedgerId, salesLedgerIds)
-                        .eq(SalesLedgerProduct::getType, 1));
+        List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().in(SalesLedgerProduct::getSalesLedgerId, salesLedgerIds).eq(SalesLedgerProduct::getType, 1));
 
         if (CollectionUtils.isNotEmpty(allProducts)) {
-            Map<Long, SalesLedger> ledgerMap = ledgers.stream()
-                    .collect(Collectors.toMap(SalesLedger::getId, Function.identity()));
+            Map<Long, SalesLedger> ledgerMap = ledgers.stream().collect(Collectors.toMap(SalesLedger::getId, Function.identity()));
 
             List<SalesInvoicesDto.InvoiceOrderGroupDto> groups = new ArrayList<>();
             BigDecimal totalQty = BigDecimal.ZERO;
@@ -1662,8 +1499,7 @@
                 BigDecimal groupArea = BigDecimal.ZERO;
 
                 for (SalesLedgerProduct p : products) {
-                    String widthHeight = (p.getWidth() != null ? p.getWidth().stripTrailingZeros().toPlainString() : "0") +
-                            " * " + (p.getHeight() != null ? p.getHeight().stripTrailingZeros().toPlainString() : "0");
+                    String widthHeight = (p.getWidth() != null ? p.getWidth().stripTrailingZeros().toPlainString() : "0") + " * " + (p.getHeight() != null ? p.getHeight().stripTrailingZeros().toPlainString() : "0");
                     String floorCode = StringUtils.defaultString(p.getFloorCode(), "");
                     String remark = StringUtils.defaultString(p.getRemark(), "");
                     String processReq = StringUtils.defaultString(p.getProcessRequirement(), "");
@@ -1731,8 +1567,7 @@
         }
 
         // 鏌ヨ浜у搧鍒楄〃
-        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(
-                new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId));
+        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId));
 
         // 鏌ヨ瀹㈡埛鍦板潃
         String fullAddress = "";
@@ -1762,9 +1597,7 @@
                 dto.setProductName(p.getSpecificationModel());
 
                 // 瀹�*楂�=鏁伴噺
-                String specification = (p.getWidth() != null ? p.getWidth().stripTrailingZeros().toPlainString() : "0") + "*" +
-                        (p.getHeight() != null ? p.getHeight().stripTrailingZeros().toPlainString() : "0") + "=" +
-                        (p.getQuantity() != null ? p.getQuantity().stripTrailingZeros().toPlainString() : "0");
+                String specification = (p.getWidth() != null ? p.getWidth().stripTrailingZeros().toPlainString() : "0") + "*" + (p.getHeight() != null ? p.getHeight().stripTrailingZeros().toPlainString() : "0") + "=" + (p.getQuantity() != null ? p.getQuantity().stripTrailingZeros().toPlainString() : "0");
                 dto.setSpecification(specification);
 
                 // 瀹㈡埛鍦板潃 + 妤煎眰缂栧彿
@@ -1793,22 +1626,14 @@
         return next;
     }
 
-    public <T, S> void updateMainContractAmount(
-            Long mainId,
-            List<T> subList,
-            Function<T, BigDecimal> amountGetter,
-            BaseMapper<S> mainMapper,
-            Class<S> mainEntityClass) {
+    public <T, S> void updateMainContractAmount(Long mainId, List<T> subList, Function<T, BigDecimal> amountGetter, BaseMapper<S> mainMapper, Class<S> mainEntityClass) {
 
         if (mainId == null || subList == null || subList.isEmpty()) {
             return;
         }
 
         // 璁$畻瀛愯〃閲戦鎬诲拰
-        BigDecimal totalAmount = subList.stream()
-                .map(amountGetter)
-                .filter(Objects::nonNull)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        BigDecimal totalAmount = subList.stream().map(amountGetter).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
 
         // 鏋勯�犱富琛ㄦ洿鏂板璞�
         try {
@@ -1978,19 +1803,12 @@
 
     @Override
     public List<Customer> shippedCustomers() {
-        List<SalesLedger> ledgers = list(Wrappers.<SalesLedger>lambdaQuery()
-                .eq(SalesLedger::getDeliveryStatus, 5)
-                .isNotNull(SalesLedger::getCustomerId)
-                .select(SalesLedger::getCustomerId));
+        List<SalesLedger> ledgers = list(Wrappers.<SalesLedger>lambdaQuery().eq(SalesLedger::getDeliveryStatus, 5).isNotNull(SalesLedger::getCustomerId).select(SalesLedger::getCustomerId));
         if (CollectionUtils.isEmpty(ledgers)) {
             return Collections.emptyList();
         }
-        Set<Long> customerIds = ledgers.stream()
-                .map(SalesLedger::getCustomerId)
-                .collect(Collectors.toCollection(LinkedHashSet::new));
-        return customerMapper.selectList(Wrappers.<Customer>lambdaQuery()
-                .in(Customer::getId, customerIds)
-                .orderByAsc(Customer::getCustomerName));
+        Set<Long> customerIds = ledgers.stream().map(SalesLedger::getCustomerId).collect(Collectors.toCollection(LinkedHashSet::new));
+        return customerMapper.selectList(Wrappers.<Customer>lambdaQuery().in(Customer::getId, customerIds).orderByAsc(Customer::getCustomerName));
     }
 
     @Override
@@ -2031,8 +1849,7 @@
             }
             inboundQtyByLineId.merge(inbound.getId(), inboundQty, BigDecimal::add);
         }
-        List<SalesLedgerProduct> selectedProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery()
-                .in(SalesLedgerProduct::getId, inboundQtyByLineId.keySet()));
+        List<SalesLedgerProduct> selectedProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().in(SalesLedgerProduct::getId, inboundQtyByLineId.keySet()));
         if (CollectionUtils.isEmpty(selectedProducts)) {
             throw new ServiceException("鍏ュ簱澶辫触,鏈煡璇㈠埌鍏ュ簱浜у搧");
         }
@@ -2054,17 +1871,10 @@
         if (StringUtils.isEmpty(approveUserIds)) {
             throw new ServiceException("鍏ュ簱澶辫触,璇烽�夋嫨瀹℃壒浜�");
         }
-        String lines = inboundQtyByLineId.entrySet().stream()
-                .map(e -> e.getKey() + "@" + e.getValue().stripTrailingZeros().toPlainString())
-                .collect(Collectors.joining(","));
+        String lines = inboundQtyByLineId.entrySet().stream().map(e -> e.getKey() + "@" + e.getValue().stripTrailingZeros().toPlainString()).collect(Collectors.joining(","));
         String reason = "閿�鍞壂鐮佸悎鏍煎叆搴撳鎵�:" + salesLedger.getSalesContractNo();
         String remark = "scanQualified:" + salesLedger.getId() + ":" + lines;
-        ApproveProcess exist = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode())
-                .eq(ApproveProcess::getApproveRemark, remark)
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .orderByDesc(ApproveProcess::getCreateTime)
-                .last("limit 1"));
+        ApproveProcess exist = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>().eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode()).eq(ApproveProcess::getApproveRemark, remark).eq(ApproveProcess::getApproveDelete, 0).orderByDesc(ApproveProcess::getCreateTime).last("limit 1"));
         if (exist != null && !Objects.equals(exist.getApproveStatus(), 3)) {
             throw new ServiceException("鍏ュ簱澶辫触,璇ョ敵璇峰凡鎻愪氦瀹℃壒");
         }
@@ -2137,8 +1947,7 @@
             dbProduct.fillRemainingQuantity();
             salesLedgerProductMapper.updateById(dbProduct);
         }
-        List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(
-                Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledgerId));
+        List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledgerId));
         boolean anyInbound = ledgerAllProducts.stream().anyMatch(p -> {
             BigDecimal sq = p.getStockedQuantity();
             return sq != null && sq.compareTo(BigDecimal.ZERO) > 0;
@@ -2178,8 +1987,7 @@
             }
             inboundQtyByLineId.merge(inbound.getId(), inboundQty, BigDecimal::add);
         }
-        List<SalesLedgerProduct> selectedProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery()
-                .in(SalesLedgerProduct::getId, inboundQtyByLineId.keySet()));
+        List<SalesLedgerProduct> selectedProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().in(SalesLedgerProduct::getId, inboundQtyByLineId.keySet()));
         if (CollectionUtils.isEmpty(selectedProducts)) {
             throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,鏈煡璇㈠埌鍏ュ簱浜у搧");
         }
@@ -2201,17 +2009,10 @@
         if (StringUtils.isEmpty(approveUserIds)) {
             throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,璇烽�夋嫨瀹℃壒浜�");
         }
-        String lines = inboundQtyByLineId.entrySet().stream()
-                .map(e -> e.getKey() + "@" + e.getValue().stripTrailingZeros().toPlainString())
-                .collect(Collectors.joining(","));
+        String lines = inboundQtyByLineId.entrySet().stream().map(e -> e.getKey() + "@" + e.getValue().stripTrailingZeros().toPlainString()).collect(Collectors.joining(","));
         String reason = "閿�鍞壂鐮佷笉鍚堟牸鍏ュ簱瀹℃壒:" + salesLedger.getSalesContractNo();
         String remark = "scanUnqualified:" + salesLedger.getId() + ":" + lines;
-        ApproveProcess exist = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode())
-                .eq(ApproveProcess::getApproveRemark, remark)
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .orderByDesc(ApproveProcess::getCreateTime)
-                .last("limit 1"));
+        ApproveProcess exist = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>().eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode()).eq(ApproveProcess::getApproveRemark, remark).eq(ApproveProcess::getApproveDelete, 0).orderByDesc(ApproveProcess::getCreateTime).last("limit 1"));
         if (exist != null && !Objects.equals(exist.getApproveStatus(), 3)) {
             throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,璇ョ敵璇峰凡鎻愪氦瀹℃壒");
         }
@@ -2258,8 +2059,7 @@
             if (dbProduct.getProductModelId() == null) {
                 throw new ServiceException("涓嶅悎鏍煎叆搴撳け璐�,浜у搧瑙勬牸鏈淮鎶�,鏃犳硶鍏ュ簱");
             }
-            stockUtils.addUnStock(ledgerId, dbProduct.getId(), dbProduct.getProductModelId(), inboundThisLine,
-                    StockInUnQualifiedRecordTypeEnum.SALES_SCAN_UNSTOCK_IN.getCode(), dbProduct.getId());
+            stockUtils.addUnStock(ledgerId, dbProduct.getId(), dbProduct.getProductModelId(), inboundThisLine, StockInUnQualifiedRecordTypeEnum.SALES_SCAN_UNSTOCK_IN.getCode(), dbProduct.getId());
             BigDecimal oldUnStocked = dbProduct.getUnqualifiedStockedQuantity() == null ? BigDecimal.ZERO : dbProduct.getUnqualifiedStockedQuantity();
             dbProduct.setUnqualifiedStockedQuantity(oldUnStocked.add(inboundThisLine));
             dbProduct.fillRemainingQuantity();
@@ -2271,20 +2071,13 @@
         if (StringUtils.isNotEmpty(approveUserIds)) {
             return approveUserIds;
         }
-        LambdaQueryWrapper<ApproveProcess> wrapper = new LambdaQueryWrapper<ApproveProcess>()
-                .eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode())
-                .eq(ApproveProcess::getApproveDelete, 0)
-                .orderByDesc(ApproveProcess::getCreateTime)
-                .last("limit 1");
+        LambdaQueryWrapper<ApproveProcess> wrapper = new LambdaQueryWrapper<ApproveProcess>().eq(ApproveProcess::getApproveType, ApproveTypeEnum.STOCK_IN.getCode()).eq(ApproveProcess::getApproveDelete, 0).orderByDesc(ApproveProcess::getCreateTime).last("limit 1");
         if (Objects.equals(bizType, INBOUND_BIZ_TYPE_WEB)) {
-            wrapper.likeRight(ApproveProcess::getApproveReason, "鍏ュ簱瀹℃壒:")
-                    .likeRight(ApproveProcess::getApproveRemark, "salesStock:" + salesLedgerId + ":");
+            wrapper.likeRight(ApproveProcess::getApproveReason, "鍏ュ簱瀹℃壒:").likeRight(ApproveProcess::getApproveRemark, "salesStock:" + salesLedgerId + ":");
         } else if (Objects.equals(bizType, INBOUND_BIZ_TYPE_SCAN_QUALIFIED)) {
-            wrapper.likeRight(ApproveProcess::getApproveReason, "閿�鍞壂鐮佸悎鏍煎叆搴撳鎵�:")
-                    .likeRight(ApproveProcess::getApproveRemark, "scanQualified:" + salesLedgerId + ":");
+            wrapper.likeRight(ApproveProcess::getApproveReason, "閿�鍞壂鐮佸悎鏍煎叆搴撳鎵�:").likeRight(ApproveProcess::getApproveRemark, "scanQualified:" + salesLedgerId + ":");
         } else if (Objects.equals(bizType, INBOUND_BIZ_TYPE_SCAN_UNQUALIFIED)) {
-            wrapper.likeRight(ApproveProcess::getApproveReason, "閿�鍞壂鐮佷笉鍚堟牸鍏ュ簱瀹℃壒:")
-                    .likeRight(ApproveProcess::getApproveRemark, "scanUnqualified:" + salesLedgerId + ":");
+            wrapper.likeRight(ApproveProcess::getApproveReason, "閿�鍞壂鐮佷笉鍚堟牸鍏ュ簱瀹℃壒:").likeRight(ApproveProcess::getApproveRemark, "scanUnqualified:" + salesLedgerId + ":");
         } else {
             return null;
         }
@@ -2356,8 +2149,7 @@
             dbProduct.fillRemainingQuantity();
             salesLedgerProductMapper.updateById(dbProduct);
         }
-        List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(
-                Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledgerId));
+        List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledgerId));
         boolean anyInbound = ledgerAllProducts.stream().anyMatch(p -> {
             BigDecimal sq = p.getStockedQuantity();
             return sq != null && sq.compareTo(BigDecimal.ZERO) > 0;
@@ -2422,12 +2214,585 @@
                 throw new ServiceException("涓嶅悎鏍煎嚭搴撳け璐�,鍑哄簱鏁伴噺涓嶈兘澶т簬涓嶅悎鏍煎叆搴撴暟閲�");
             }
             stockUtils.assertUnqualifiedAvailable(dbProduct.getProductModelId(), outboundThisLine);
-            stockUtils.subtractUnStock(ledgerId, dbProduct.getId(), dbProduct.getProductModelId(), outboundThisLine,
-                    StockOutUnQualifiedRecordTypeEnum.SALE_SCAN_UNSTOCK_OUT.getCode(), dbProduct.getId());
+            stockUtils.subtractUnStock(ledgerId, dbProduct.getId(), dbProduct.getProductModelId(), outboundThisLine, StockOutUnQualifiedRecordTypeEnum.SALE_SCAN_UNSTOCK_OUT.getCode(), dbProduct.getId());
 
             dbProduct.setUnqualifiedShippedQuantity(unShipped.add(outboundThisLine));
             dbProduct.fillRemainingQuantity();
             salesLedgerProductMapper.updateById(dbProduct);
         }
     }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void shippingImport(MultipartFile file) {
+        if (file == null || file.isEmpty()) {
+            throw new ServiceException("瀵煎叆澶辫触,瀵煎叆鏂囦欢鏁版嵁涓嶈兘涓虹┖");
+        }
+        List<SalesShippingImportDto> list;
+        try {
+            ExcelUtil<SalesShippingImportDto> excelUtil = new ExcelUtil<>(SalesShippingImportDto.class);
+            list = excelUtil.importExcel(file.getInputStream());
+        } catch (Exception e) {
+            log.error("閿�鍞彂璐у巻鍙叉暟鎹鍏�-宸插彂璐у鍏ュけ璐�: {}", e.getMessage());
+            throw new ServiceException("瀵煎叆澶辫触,鏁版嵁璇诲彇寮傚父");
+        }
+        if (CollectionUtils.isEmpty(list)) {
+            throw new ServiceException("瀵煎叆澶辫触,鏂囦欢鏁版嵁涓虹┖");
+        }
+        Map<String, List<SalesShippingImportDto>> groupedByOrderNo = list.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(SalesShippingImportDto::getOrderNo, LinkedHashMap::new, Collectors.toList()));
+
+        for (Map.Entry<String, List<SalesShippingImportDto>> entry : groupedByOrderNo.entrySet()) {
+            String orderNo = entry.getKey();
+            if (!StringUtils.hasText(orderNo)) {
+                throw new ServiceException("瀵煎叆澶辫触,瀛樺湪璁㈠崟缂栧彿涓虹┖鐨勬暟鎹�");
+            }
+            List<SalesShippingImportDto> rowList = entry.getValue();
+            if (CollectionUtils.isEmpty(rowList)) {
+                continue;
+            }
+            SalesLedger ledger = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>().eq(SalesLedger::getSalesContractNo, orderNo).last("LIMIT 1"));
+            if (ledger == null) {
+                throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]涓嶅瓨鍦�,鏃犳硶琛ュ綍宸插彂璐ф暟鎹�");
+            }
+            List<SalesLedgerProduct> dbProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()).eq(SalesLedgerProduct::getType, SaleEnum.SALE.getCode()));
+            if (CollectionUtils.isEmpty(dbProducts)) {
+                throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]娌℃湁閿�鍞骇鍝�,鏃犳硶琛ュ綍鍙戣揣");
+            }
+            Map<String, List<SalesLedgerProduct>> productByCategory = dbProducts.stream().collect(Collectors.groupingBy(p -> StringUtils.hasText(p.getProductCategory()) ? p.getProductCategory().trim() : ""));
+            Set<String> importedRowKeys = new HashSet<>();
+
+            for (SalesShippingImportDto row : rowList) {
+                BigDecimal shipQty = defaultDecimal(row.getQuantity());
+                if (shipQty.compareTo(BigDecimal.ZERO) <= 0) {
+                    throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]瀛樺湪鏁伴噺灏忎簬绛変簬0鐨勬暟鎹�");
+                }
+                String rowKey = buildShippingRowKey(ledger.getId(), row);
+                if (!importedRowKeys.add(rowKey)) {
+                    throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]瀛樺湪閲嶅鍙戣揣鏄庣粏琛�");
+                }
+                Map<SalesLedgerProduct, BigDecimal> allocations = allocateShippingProductLines(orderNo, row, productByCategory, dbProducts);
+                for (Map.Entry<SalesLedgerProduct, BigDecimal> alloc : allocations.entrySet()) {
+                    SalesLedgerProduct dbProduct = alloc.getKey();
+                    BigDecimal allocQty = alloc.getValue();
+                    if (dbProduct.getProductModelId() == null) {
+                        throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]浜у搧瑙勬牸鏈淮鎶�,鏃犳硶琛ュ綍鍑哄簱");
+                    }
+                    BigDecimal oldShipped = defaultDecimal(dbProduct.getShippedQuantity());
+                    BigDecimal newShipped = oldShipped.add(allocQty);
+                    dbProduct.setStockedQuantity(defaultDecimal(dbProduct.getQuantity()));
+                    dbProduct.setShippedQuantity(newShipped);
+                    updateProductStockStatus(dbProduct);
+                    dbProduct.fillRemainingQuantity();
+                    updateProductShipStatus(dbProduct);
+                    salesLedgerProductMapper.updateById(dbProduct);
+
+                    ShippingInfo shippingInfo = new ShippingInfo();
+                    shippingInfo.setSalesLedgerId(ledger.getId());
+                    shippingInfo.setSalesLedgerProductId(dbProduct.getId());
+                    shippingInfo.setStatus("宸插彂璐�");
+                    shippingInfo.setShippingNo(row.getShippingNo());
+                    shippingInfo.setType("璐ц溅");
+                    shippingInfo.setShippingCarNumber("鏃�");
+                    shippingInfo.setShippingDate(row.getReportDate());
+                    long existedShippingCount = shippingInfoMapper.selectCount(new LambdaQueryWrapper<ShippingInfo>().eq(ShippingInfo::getSalesLedgerId, ledger.getId()).eq(ShippingInfo::getSalesLedgerProductId, dbProduct.getId()).eq(StringUtils.hasText(row.getShippingNo()), ShippingInfo::getShippingNo, row.getShippingNo()).eq(row.getReportDate() != null, ShippingInfo::getShippingDate, row.getReportDate()));
+                    if (existedShippingCount > 0) {
+                        throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]瀛樺湪閲嶅鍙戣揣璁板綍,璇峰嬁閲嶅瀵煎叆");
+                    }
+                    shippingInfoMapper.insert(shippingInfo);
+                }
+            }
+
+            List<SalesLedgerProduct> latestProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()).eq(SalesLedgerProduct::getType, SaleEnum.SALE.getCode()));
+            boolean allShipped = CollectionUtils.isNotEmpty(latestProducts) && latestProducts.stream().allMatch(p -> {
+                BigDecimal qty = defaultDecimal(p.getQuantity());
+                BigDecimal shipped = defaultDecimal(p.getShippedQuantity());
+                return shipped.compareTo(qty) >= 0;
+            });
+            if (allShipped && rowList.get(0).getReportDate() != null) {
+                ledger.setDeliveryDate(DateUtils.toLocalDate(rowList.get(0).getReportDate()));
+            }
+            ledger.setDeliveryStatus(allShipped ? 5 : 1);
+            salesLedgerMapper.updateById(ledger);
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void notShippingImport(MultipartFile file) {
+        if (file == null || file.isEmpty()) {
+            throw new ServiceException("瀵煎叆澶辫触,瀵煎叆鏂囦欢鏁版嵁涓嶈兘涓虹┖");
+        }
+        List<SalesNotShippingImportDto> list;
+        try {
+            ExcelUtil<SalesNotShippingImportDto> excelUtil = new ExcelUtil<>(SalesNotShippingImportDto.class);
+            list = excelUtil.importExcel(file.getInputStream());
+        } catch (Exception e) {
+            log.error("閿�鍞彂璐у巻鍙叉暟鎹鍏�-鏈彂璐у鍏ュけ璐�: {}", e.getMessage());
+            throw new ServiceException("瀵煎叆澶辫触,鏁版嵁璇诲彇寮傚父");
+        }
+        if (CollectionUtils.isEmpty(list)) {
+            throw new ServiceException("瀵煎叆澶辫触,鏂囦欢鏁版嵁涓虹┖");
+        }
+        List<SysUser> allUsers = sysUserMapper.selectList(null);
+        Map<String, SysUser> userByNickNameMap = allUsers.stream().filter(Objects::nonNull).filter(u -> StringUtils.hasText(u.getNickName())).collect(Collectors.toMap(SysUser::getNickName, Function.identity(), (a, b) -> a));
+        Map<String, SysUser> userByUserNameMap = allUsers.stream().filter(Objects::nonNull).filter(u -> StringUtils.hasText(u.getUserName())).collect(Collectors.toMap(SysUser::getUserName, Function.identity(), (a, b) -> a));
+
+        Map<String, Customer> customerNameMap = customerMapper.selectList(null).stream().filter(Objects::nonNull).filter(c -> StringUtils.hasText(c.getCustomerName())).collect(Collectors.toMap(Customer::getCustomerName, Function.identity(), (a, b) -> a));
+        List<CustomerRegions> allRegions = customerRegionsService.list();
+        CustomerRegions hebiRegion = allRegions.stream().filter(Objects::nonNull).filter(r -> "楣ゅ".equals(r.getRegionsName())).findFirst().orElseGet(() -> {
+            CustomerRegions region = new CustomerRegions();
+            region.setRegionsName("楣ゅ");
+            region.setParentId(0L);
+            customerRegionsService.save(region);
+            return region;
+        });
+        Map<String, Product> productNameMap = productMapper.selectList(null).stream().filter(Objects::nonNull).filter(p -> StringUtils.hasText(p.getProductName())).collect(Collectors.toMap(Product::getProductName, Function.identity(), (a, b) -> a));
+        Product finishedGoodsParent = productNameMap.get("鎴愬搧");
+        if (finishedGoodsParent == null || finishedGoodsParent.getId() == null) {
+            finishedGoodsParent = new Product();
+            finishedGoodsParent.setProductName("鎴愬搧");
+            finishedGoodsParent.setParentId(null);
+            productMapper.insert(finishedGoodsParent);
+            productNameMap.put("鎴愬搧", finishedGoodsParent);
+        }
+        Map<String, ProductModel> productModelKeyMap = productModelMapper.selectList(null).stream().filter(Objects::nonNull).filter(m -> m.getProductId() != null && StringUtils.hasText(m.getModel())).collect(Collectors.toMap(m -> buildProductModelKey(m.getProductId(), m.getModel()), Function.identity(), (a, b) -> a));
+
+        List<String> extraProcessNames = Arrays.asList("鎵撳瓟", "鎸栫己", "瀹夊叏瑙�", "纾ㄨ竟");
+        Map<String, SalesLedgerProductProcess> processMap = salesLedgerProductProcessService.list(new LambdaQueryWrapper<SalesLedgerProductProcess>().in(SalesLedgerProductProcess::getProcessName, extraProcessNames)).stream().filter(Objects::nonNull).filter(p -> StringUtils.hasText(p.getProcessName())).collect(Collectors.toMap(SalesLedgerProductProcess::getProcessName, Function.identity(), (a, b) -> a));
+        List<ProcessRoute> processRoutes = processRouteMapper.selectList(new LambdaQueryWrapper<ProcessRoute>().eq(ProcessRoute::getProductModelId, 0L));
+        Map<String, ProcessRoute> routeNameMap = processRoutes.stream().filter(Objects::nonNull).filter(r -> StringUtils.hasText(r.getProcessRouteName())).collect(Collectors.toMap(r -> normalizeRouteFlowKey(r.getProcessRouteName()), Function.identity(), this::chooseBetterRoute));
+        Map<Long, List<ProcessRouteItem>> routeItemMap = Collections.emptyMap();
+        List<Long> routeIds = processRoutes.stream().map(ProcessRoute::getId).filter(Objects::nonNull).collect(Collectors.toList());
+        if (CollectionUtils.isNotEmpty(routeIds)) {
+            routeItemMap = processRouteItemMapper.selectList(new LambdaQueryWrapper<ProcessRouteItem>().in(ProcessRouteItem::getRouteId, routeIds).orderByAsc(ProcessRouteItem::getDragSort).orderByAsc(ProcessRouteItem::getId)).stream().filter(Objects::nonNull).collect(Collectors.groupingBy(ProcessRouteItem::getRouteId));
+        }
+
+        Map<String, List<SalesNotShippingImportDto>> groupedByOrderNo = list.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(SalesNotShippingImportDto::getOrderNo, LinkedHashMap::new, Collectors.toList()));
+
+        for (Map.Entry<String, List<SalesNotShippingImportDto>> entry : groupedByOrderNo.entrySet()) {
+            String orderNo = entry.getKey();
+            if (!StringUtils.hasText(orderNo)) {
+                throw new ServiceException("瀵煎叆澶辫触,瀛樺湪璁㈠崟缂栧彿涓虹┖鐨勬暟鎹�");
+            }
+            List<SalesNotShippingImportDto> rowList = entry.getValue();
+            if (CollectionUtils.isEmpty(rowList)) {
+                continue;
+            }
+            SalesNotShippingImportDto first = rowList.get(0);
+            SalesLedger exists = salesLedgerMapper.selectOne(new LambdaQueryWrapper<SalesLedger>().eq(SalesLedger::getSalesContractNo, orderNo).last("LIMIT 1"));
+            if (exists != null) {
+                throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]宸插瓨鍦�");
+            }
+
+            SalesLedger ledger = new SalesLedger();
+            SysUser creatorUser = resolveImportUser(first.getCreator(), userByNickNameMap, userByUserNameMap, "鍒跺崟鍛�", orderNo);
+            ledger.setSalesContractNo(orderNo);
+            ledger.setCustomerContractNo(first.getContractNo());
+            ledger.setProjectName(first.getProjectName());
+            ledger.setSalesman(first.getSalesman());
+            Customer customer = getOrCreateImportCustomer(first.getCustomerName(), customerNameMap, hebiRegion.getId());
+            ledger.setCustomerName(customer.getCustomerName());
+            ledger.setRemarks(first.getRemark());
+            ledger.setEntryPerson(String.valueOf(creatorUser.getUserId()));
+            ledger.setEntryDate(first.getReportDate());
+            if (first.getReportDate() != null) {
+                ledger.setExecutionDate(DateUtils.toLocalDate(first.getReportDate()));
+            }
+            ledger.setDeliveryDate(first.getDeliveryDeadline() == null ? (first.getReportDate() == null ? LocalDate.now().plusDays(7) : DateUtils.toLocalDate(first.getReportDate()).plusDays(7)) : DateUtils.toLocalDate(first.getDeliveryDeadline()));
+            ledger.setDeliveryStatus(1);
+            ledger.setStockStatus(0);
+
+            ledger.setCustomerId(customer.getId());
+            ledger.setCustomerContractNo(StringUtils.hasText(ledger.getCustomerContractNo()) ? ledger.getCustomerContractNo() : customer.getTaxpayerIdentificationNumber());
+
+            ledger.setContractAmount(BigDecimal.ZERO);
+            salesLedgerMapper.insert(ledger);
+            bindImportProcessRoute(ledger.getId(), rowList, routeNameMap, routeItemMap);
+
+            BigDecimal contractAmount = BigDecimal.ZERO;
+            for (SalesNotShippingImportDto row : rowList) {
+                SalesLedgerProduct product = new SalesLedgerProduct();
+                product.setSalesLedgerId(ledger.getId());
+                product.setType(SaleEnum.SALE.getCode());
+                String specificationModel = buildSpecificationModel(row);
+                Product importProduct = resolveOrCreateImportProduct(row, productNameMap, finishedGoodsParent, orderNo);
+                ProductModel importProductModel = resolveOrCreateImportProductModel(importProduct, specificationModel, row.getGlassThickness(), productModelKeyMap);
+                product.setProductCategory(row.getProductSubCategory());
+                product.setSpecificationModel(specificationModel);
+                product.setProductId(importProduct.getId());
+                product.setProductModelId(importProductModel.getId());
+                product.setFloorCode(row.getFloorNo());
+                product.setWidth(defaultDecimal(row.getWidth()));
+                product.setHeight(defaultDecimal(row.getHeight()));
+                product.setQuantity(defaultDecimal(row.getQuantity()));
+                product.setActualPieceArea(defaultDecimal(row.getActualSingleArea()));
+                product.setActualTotalArea(defaultDecimal(row.getActualTotalArea()));
+                product.setSettlePieceArea(defaultDecimal(row.getSettlementSingleArea()));
+                product.setSettleTotalArea(defaultDecimal(row.getSettlementTotalArea()));
+                product.setTaxInclusiveUnitPrice(defaultDecimal(row.getUnitPrice()));
+                product.setPerimeter(defaultDecimal(row.getPerimeter()));
+                product.setHeavyBox(defaultDecimal(row.getHeavyBox()));
+                product.setProcessRequirement(row.getProcessRequirement());
+                product.setRemark(StringUtils.hasText(row.getAuditRemark()) ? row.getAuditRemark() : row.getRemark());
+                product.setApproveStatus(0);
+                product.setProductStockStatus(0);
+                product.setRegister(creatorUser.getNickName());
+                product.setRegisterDate(row.getReportDate() == null ? LocalDateTime.now() : LocalDateTime.ofInstant(row.getReportDate().toInstant(), ZoneId.systemDefault()));
+
+                BigDecimal qty = defaultDecimal(product.getQuantity());
+                if (qty.compareTo(BigDecimal.ZERO) <= 0) {
+                    throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]瀛樺湪鏁伴噺灏忎簬绛変簬0鐨勬暟鎹�");
+                }
+
+                BigDecimal lineAmount = defaultDecimal(row.getGlassAmount()).add(defaultDecimal(row.getOtherProcessFee()));
+                if (lineAmount.compareTo(BigDecimal.ZERO) <= 0 && product.getTaxInclusiveUnitPrice().compareTo(BigDecimal.ZERO) > 0 && product.getSettleTotalArea().compareTo(BigDecimal.ZERO) > 0) {
+                    lineAmount = product.getTaxInclusiveUnitPrice().multiply(product.getSettleTotalArea()).setScale(2, RoundingMode.HALF_UP);
+                }
+                product.setTaxRate(BigDecimal.ZERO);
+                product.setTaxInclusiveTotalPrice(lineAmount);
+                product.setTaxExclusiveTotalPrice(lineAmount);
+                product.setNoInvoiceNum(qty);
+                product.setNoInvoiceAmount(lineAmount);
+                product.setPendingInvoiceTotal(lineAmount);
+                product.fillRemainingQuantity();
+                salesLedgerProductMapper.insert(product);
+
+                List<SalesLedgerProductProcess> bindProcessList = buildImportProcessBinds(row, processMap);
+                if (CollectionUtils.isNotEmpty(bindProcessList)) {
+                    salesLedgerProductProcessBindService.updateProductProcessBind(bindProcessList, product.getId());
+                }
+
+                salesLedgerProductServiceImpl.addProductionData(product);
+                contractAmount = contractAmount.add(lineAmount);
+            }
+
+            ledger.setContractAmount(contractAmount);
+            salesLedgerMapper.updateById(ledger);
+        }
+    }
+
+    private List<SalesLedgerProductProcess> buildImportProcessBinds(SalesNotShippingImportDto row, Map<String, SalesLedgerProductProcess> processMap) {
+        LinkedHashMap<String, Integer> processQuantityMap = new LinkedHashMap<>();
+        mergeProcessQuantity(processQuantityMap, "鎵撳瓟", toProcessQuantity(row.getDrilling()));
+        mergeProcessQuantity(processQuantityMap, "鎸栫己", toProcessQuantity(row.getNotching()));
+        mergeProcessQuantity(processQuantityMap, "瀹夊叏瑙�", toProcessQuantity(row.getSafetyCorner()));
+        mergeProcessQuantity(processQuantityMap, "纾ㄨ竟", toProcessQuantity(row.getGrindingIrregular()));
+
+        List<SalesLedgerProductProcess> result = new ArrayList<>();
+        for (Map.Entry<String, Integer> entry : processQuantityMap.entrySet()) {
+            if (entry.getValue() == null || entry.getValue() <= 0) {
+                continue;
+            }
+            SalesLedgerProductProcess process = processMap.get(entry.getKey());
+            if (process == null || process.getId() == null) {
+                log.warn("瀵煎叆宸ヨ壓鏈壘鍒伴厤缃�, processName={}, orderNo={}", entry.getKey(), row.getOrderNo());
+                continue;
+            }
+            SalesLedgerProductProcess bind = new SalesLedgerProductProcess();
+            bind.setId(process.getId());
+            bind.setQuantity(entry.getValue());
+            result.add(bind);
+        }
+        return result;
+    }
+
+    private void bindImportProcessRoute(Long salesLedgerId, List<SalesNotShippingImportDto> rowList, Map<String, ProcessRoute> routeNameMap, Map<Long, List<ProcessRouteItem>> routeItemMap) {
+        String flowKey = rowList.stream().map(SalesNotShippingImportDto::getProcessFlow).filter(StringUtils::hasText).map(this::normalizeRouteFlowKey).filter(StringUtils::hasText).findFirst().orElse("");
+        if (!StringUtils.hasText(flowKey)) {
+            throw new ServiceException("瀵煎叆澶辫触,璁㈠崟宸ヨ壓娴佺▼涓嶈兘涓虹┖");
+        }
+        ProcessRoute route = routeNameMap.get(flowKey);
+        if (route == null || route.getId() == null) {
+            route = createImportProcessRoute(flowKey, routeNameMap, routeItemMap);
+        }
+        List<ProcessRouteItem> routeItems = routeItemMap.getOrDefault(route.getId(), Collections.emptyList());
+        if (CollectionUtils.isEmpty(routeItems)) {
+            route = createImportProcessRoute(flowKey, routeNameMap, routeItemMap);
+            routeItems = routeItemMap.getOrDefault(route.getId(), Collections.emptyList());
+            if (CollectionUtils.isEmpty(routeItems)) {
+                throw new ServiceException("瀵煎叆澶辫触,宸ヨ壓璺嚎[" + flowKey + "]鏈厤缃伐鑹鸿妭鐐�");
+            }
+        }
+        List<SalesLedgerProcessRoute> bindList = new ArrayList<>();
+        for (ProcessRouteItem item : routeItems) {
+            SalesLedgerProcessRoute bind = new SalesLedgerProcessRoute();
+            bind.setSalesLedgerId(salesLedgerId);
+            bind.setProcessRouteId(route.getId());
+            bind.setProcessRouteItemId(item.getId());
+            bind.setDragSort(item.getDragSort());
+            bindList.add(bind);
+        }
+        salesLedgerProcessRouteService.saveBatch(bindList);
+    }
+
+    private ProcessRoute createImportProcessRoute(String flowKey, Map<String, ProcessRoute> routeNameMap, Map<Long, List<ProcessRouteItem>> routeItemMap) {
+        List<String> processNames = Arrays.stream(flowKey.split("->")).filter(StringUtils::hasText).map(String::trim).collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(processNames)) {
+            throw new ServiceException("瀵煎叆澶辫触,宸ヨ壓璺嚎[" + flowKey + "]瑙f瀽澶辫触");
+        }
+        ProcessRoute route = new ProcessRoute();
+        route.setProductModelId(0L);
+        route.setProcessRouteName(flowKey);
+        route.setIsDefault(0);
+        route.setDescription("");
+        route.setProcessRouteCode("AUTO_" + System.currentTimeMillis());
+        processRouteMapper.insert(route);
+        List<ProcessRouteItem> routeItems = new ArrayList<>();
+        for (int i = 0; i < processNames.size(); i++) {
+            ProcessRouteItem item = new ProcessRouteItem();
+            item.setRouteId(route.getId());
+            item.setProductModelId(0L);
+            item.setProcessId(0L);
+            item.setProcessName(processNames.get(i));
+            item.setDragSort(i + 1);
+            item.setIsQuality(Boolean.TRUE);
+            processRouteItemMapper.insert(item);
+            routeItems.add(item);
+        }
+        routeNameMap.put(flowKey, route);
+        routeItemMap.put(route.getId(), routeItems);
+        return route;
+    }
+
+    private void mergeProcessQuantity(Map<String, Integer> processQuantityMap, String processName, Integer quantity) {
+        if (!StringUtils.hasText(processName) || quantity == null || quantity <= 0) {
+            return;
+        }
+        Integer old = processQuantityMap.get(processName);
+        if (old == null || old <= 0) {
+            processQuantityMap.put(processName, quantity);
+        }
+    }
+
+    private String normalizeRouteFlowKey(String processFlow) {
+        if (!StringUtils.hasText(processFlow)) {
+            return "";
+        }
+        return Arrays.stream(processFlow.trim().split("\\s*(?:->|鈫抾=>|锛�)\\s*")).filter(StringUtils::hasText).map(String::trim).collect(Collectors.joining("->"));
+    }
+
+    private ProcessRoute chooseBetterRoute(ProcessRoute a, ProcessRoute b) {
+        if (a == null) {
+            return b;
+        }
+        if (b == null) {
+            return a;
+        }
+        boolean aDefault = Objects.equals(a.getIsDefault(), 1);
+        boolean bDefault = Objects.equals(b.getIsDefault(), 1);
+        if (aDefault != bDefault) {
+            return aDefault ? a : b;
+        }
+        LocalDateTime aTime = a.getCreateTime();
+        LocalDateTime bTime = b.getCreateTime();
+        if (aTime == null) {
+            return b;
+        }
+        if (bTime == null) {
+            return a;
+        }
+        return bTime.isAfter(aTime) ? b : a;
+    }
+
+    private Integer toProcessQuantity(BigDecimal value) {
+        if (value == null) {
+            return null;
+        }
+        if (value.compareTo(BigDecimal.ZERO) <= 0) {
+            return 0;
+        }
+        return value.setScale(0, RoundingMode.HALF_UP).intValue();
+    }
+
+    private SysUser resolveImportUser(String rawName, Map<String, SysUser> userByNickNameMap, Map<String, SysUser> userByUserNameMap, String fieldName, String orderNo) {
+        if (!StringUtils.hasText(rawName)) {
+            throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]鐨刐" + fieldName + "]涓嶈兘涓虹┖");
+        }
+        String key = rawName.trim();
+        SysUser user = userByNickNameMap.get(key);
+        if (user == null) {
+            user = userByUserNameMap.get(key);
+        }
+        if (user == null || user.getUserId() == null) {
+            throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]鐨刐" + fieldName + ":" + key + "]鏈尮閰嶅埌浜哄憳");
+        }
+        return user;
+    }
+
+    private Customer getOrCreateImportCustomer(String customerName, Map<String, Customer> customerNameMap, Long hebiRegionId) {
+        if (!StringUtils.hasText(customerName)) {
+            throw new ServiceException("瀵煎叆澶辫触,瀹㈡埛鍚嶇О涓嶈兘涓虹┖");
+        }
+        String key = customerName.trim();
+        Customer exists = customerNameMap.get(key);
+        if (exists != null && exists.getId() != null) {
+            return exists;
+        }
+        Customer customer = new Customer();
+        customer.setCustomerName(key);
+        customer.setRegionsId(hebiRegionId);
+        customerMapper.insert(customer);
+        customerNameMap.put(key, customer);
+        return customer;
+    }
+
+    private Product resolveOrCreateImportProduct(SalesNotShippingImportDto row, Map<String, Product> productNameMap, Product finishedGoodsParent, String orderNo) {
+        String productName = row.getProductName();
+        if (StringUtils.hasText(productName)) {
+            Product product = productNameMap.get(productName.trim());
+            if (product != null && product.getId() != null) {
+                return product;
+            }
+        }
+        String productSubCategory = row.getProductSubCategory();
+        if (StringUtils.hasText(productSubCategory)) {
+            Product product = productNameMap.get(productSubCategory.trim());
+            if (product != null && product.getId() != null) {
+                return product;
+            }
+        }
+        String newProductName = buildCategoryProductName(row);
+        if (!StringUtils.hasText(newProductName)) {
+            throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]浜у搧鍚嶇О鍜屼骇鍝佸垎绫诲潎涓虹┖");
+        }
+        Product created = new Product();
+        created.setParentId(finishedGoodsParent == null ? null : finishedGoodsParent.getId());
+        created.setProductName(newProductName);
+        productMapper.insert(created);
+        productNameMap.put(newProductName, created);
+        return created;
+    }
+
+    private ProductModel resolveOrCreateImportProductModel(Product product, String modelName, BigDecimal thickness, Map<String, ProductModel> productModelKeyMap) {
+        if (product == null || product.getId() == null || !StringUtils.hasText(modelName)) {
+            throw new ServiceException("瀵煎叆澶辫触,浜у搧瑙勬牸鏁版嵁涓嶅畬鏁�");
+        }
+        String key = buildProductModelKey(product.getId(), modelName);
+        ProductModel exists = productModelKeyMap.get(key);
+        if (exists != null && exists.getId() != null) {
+            return exists;
+        }
+        ProductModel created = new ProductModel();
+        created.setProductId(product.getId());
+        created.setModel(modelName.trim());
+        created.setThickness(thickness);
+        productModelMapper.insert(created);
+        productModelKeyMap.put(key, created);
+        return created;
+    }
+
+    private String buildSpecificationModel(SalesNotShippingImportDto row) {
+        if (StringUtils.hasText(row.getProductName())) {
+            return row.getProductName().trim();
+        }
+        if (StringUtils.hasText(row.getProductSubCategory())) {
+            return row.getProductSubCategory().trim();
+        }
+        if (StringUtils.hasText(row.getProductCategory())) {
+            return row.getProductCategory().trim();
+        }
+        return "";
+    }
+
+    private String buildCategoryProductName(SalesNotShippingImportDto row) {
+        String category = row.getProductCategory();
+        String subCategory = row.getProductSubCategory();
+        if (StringUtils.hasText(category) && StringUtils.hasText(subCategory)) {
+            return category.trim() + "-" + subCategory.trim();
+        }
+        if (StringUtils.hasText(subCategory)) {
+            return subCategory.trim();
+        }
+        if (StringUtils.hasText(category)) {
+            return category.trim();
+        }
+        return "";
+    }
+
+    private String buildProductModelKey(Long productId, String modelName) {
+        return productId + "||" + modelName.trim();
+    }
+
+    private String buildCategoryProductName(SalesShippingImportDto row) {
+        String category = row.getProductCategory();
+        String subCategory = row.getProductSubCategory();
+        if (StringUtils.hasText(category) && StringUtils.hasText(subCategory)) {
+            return category.trim() + "-" + subCategory.trim();
+        }
+        if (StringUtils.hasText(subCategory)) {
+            return subCategory.trim();
+        }
+        if (StringUtils.hasText(category)) {
+            return category.trim();
+        }
+        return "";
+    }
+
+    private Integer parseInteger(String value) {
+        if (!StringUtils.hasText(value)) {
+            return 0;
+        }
+        try {
+            return new BigDecimal(value.trim()).setScale(0, RoundingMode.HALF_UP).intValue();
+        } catch (Exception e) {
+            return 0;
+        }
+    }
+
+    private Map<SalesLedgerProduct, BigDecimal> allocateShippingProductLines(String orderNo, SalesShippingImportDto row, Map<String, List<SalesLedgerProduct>> productByCategory, List<SalesLedgerProduct> allProducts) {
+        String subCategory = StringUtils.hasText(row.getProductSubCategory()) ? row.getProductSubCategory().trim() : "";
+        List<SalesLedgerProduct> candidates = productByCategory.getOrDefault(subCategory, Collections.emptyList());
+        if (CollectionUtils.isEmpty(candidates)) {
+            candidates = allProducts;
+        }
+        BigDecimal remaining = defaultDecimal(row.getQuantity());
+        Map<SalesLedgerProduct, BigDecimal> allocations = new LinkedHashMap<>();
+        for (SalesLedgerProduct p : candidates) {
+            BigDecimal qty = defaultDecimal(p.getQuantity());
+            BigDecimal shipped = defaultDecimal(p.getShippedQuantity());
+            BigDecimal canShip = qty.subtract(shipped);
+            if (canShip.compareTo(BigDecimal.ZERO) <= 0) {
+                continue;
+            }
+            BigDecimal alloc = remaining.min(canShip);
+            if (alloc.compareTo(BigDecimal.ZERO) > 0) {
+                allocations.put(p, alloc);
+                remaining = remaining.subtract(alloc);
+            }
+            if (remaining.compareTo(BigDecimal.ZERO) <= 0) {
+                return allocations;
+            }
+        }
+        if (remaining.compareTo(BigDecimal.ZERO) > 0) {
+            throw new ServiceException("瀵煎叆澶辫触,璁㈠崟缂栧彿[" + orderNo + "]浜у搧[" + subCategory + "]鍙戣揣鏁伴噺瓒呭嚭鍓╀綑鍙彂鏁伴噺");
+        }
+        return allocations;
+    }
+
+    private void updateProductShipStatus(SalesLedgerProduct dbProduct) {
+        BigDecimal qty = defaultDecimal(dbProduct.getQuantity());
+        BigDecimal shipped = defaultDecimal(dbProduct.getShippedQuantity());
+        if (shipped.compareTo(BigDecimal.ZERO) <= 0) {
+            dbProduct.setProductStockStatus(0);
+            return;
+        }
+        dbProduct.setProductStockStatus(shipped.compareTo(qty) >= 0 ? 2 : 1);
+    }
+
+    private void updateProductStockStatus(SalesLedgerProduct dbProduct) {
+        BigDecimal qty = defaultDecimal(dbProduct.getQuantity());
+        BigDecimal stocked = defaultDecimal(dbProduct.getStockedQuantity());
+        if (stocked.compareTo(BigDecimal.ZERO) <= 0) {
+            dbProduct.setProductStockStatus(0);
+            return;
+        }
+        dbProduct.setProductStockStatus(stocked.compareTo(qty) >= 0 ? 2 : 1);
+    }
+
+    private String buildShippingRowKey(Long ledgerId, SalesShippingImportDto row) {
+        String shippingNo = StringUtils.hasText(row.getShippingNo()) ? row.getShippingNo().trim() : "";
+        String dateStr = row.getReportDate() == null ? "" : String.valueOf(row.getReportDate().getTime());
+        String subCategory = StringUtils.hasText(row.getProductSubCategory()) ? row.getProductSubCategory().trim() : "";
+        return ledgerId + "|" + subCategory + "|" + shippingNo + "|" + dateStr + "|" + defaultDecimal(row.getQuantity());
+    }
 }

--
Gitblit v1.9.3