From e529b1dd89b5f2927457a284e660d489b9aa8cc8 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期三, 01 四月 2026 11:24:24 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_长治_健齿齿科器材' into dev_长治_健齿齿科器材

---
 src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java |  311 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 284 insertions(+), 27 deletions(-)

diff --git a/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java b/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
index b15f881..97354b1 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -1,11 +1,19 @@
 package com.ruoyi.stock.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.ruoyi.common.enums.StockQualifiedRecordTypeEnum;
+import com.ruoyi.basic.dto.ProductDto;
+import com.ruoyi.basic.dto.ProductTreeDto;
+import com.ruoyi.basic.mapper.ProductMapper;
+import com.ruoyi.basic.mapper.ProductModelMapper;
+import com.ruoyi.basic.pojo.Product;
+import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
@@ -19,14 +27,14 @@
 import com.ruoyi.stock.service.StockInRecordService;
 import com.ruoyi.stock.service.StockInventoryService;
 import com.ruoyi.stock.service.StockOutRecordService;
-import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
-import java.util.ArrayList;
-import java.util.List;
+import java.math.BigDecimal;
+import java.util.*;
 
 /**
  * <p>
@@ -37,13 +45,22 @@
  * @since 2026-01-21 04:16:36
  */
 @Service
-@AllArgsConstructor
 public class StockInventoryServiceImpl extends ServiceImpl<StockInventoryMapper, StockInventory> implements StockInventoryService {
 
+    @Autowired
     private  StockInventoryMapper stockInventoryMapper;
+    @Autowired
     private StockInRecordService stockInRecordService;
+    @Autowired
     private StockOutRecordService stockOutRecordService;
+    @Autowired
     private SalesLedgerProductMapper salesLedgerProductMapper;
+    @Autowired
+    private ProductMapper productMapper;
+    @Autowired
+    private ProductModelMapper productModelMapper;
+
+
     @Override
     public IPage<StockInventoryDto> pagestockInventory(Page page, StockInventoryDto stockInventoryDto) {
         return stockInventoryMapper.pagestockInventory(page, stockInventoryDto);
@@ -54,23 +71,34 @@
     @Transactional(rollbackFor = Exception.class)
     public Boolean addstockInventory(StockInventoryDto stockInventoryDto) {
         //鏂板鍏ュ簱璁板綍鍐嶆坊鍔犲簱瀛�
-        StockInRecordDto stockInRecordDto = new StockInRecordDto();
-        stockInRecordDto.setRecordId(stockInventoryDto.getRecordId());
-        stockInRecordDto.setRecordType(stockInventoryDto.getRecordType());
-        stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity());
-        stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
-        stockInRecordDto.setType("0");
-        stockInRecordService.add(stockInRecordDto);
+        if (stockInventoryDto.getRecordType() != null) {
+            StockInRecordDto stockInRecordDto = new StockInRecordDto();
+            stockInRecordDto.setRecordId(stockInventoryDto.getRecordId());
+            stockInRecordDto.setRecordType(stockInventoryDto.getRecordType());
+            stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity());
+            stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
+            stockInRecordDto.setType("0");
+            stockInRecordDto.setBatchNo(stockInventoryDto.getBatchNo());
+            stockInRecordDto.setCustomer(stockInventoryDto.getCustomer());
+            stockInRecordService.add(stockInRecordDto);
+        }
         //鍐嶈繘琛屾柊澧炲簱瀛樻暟閲忓簱瀛�
         //鍏堟煡璇㈠簱瀛樿〃涓殑浜у搧鏄惁瀛樺湪锛屼笉瀛樺湪鏂板锛屽瓨鍦ㄦ洿鏂�
-        StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()));
+        StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda()
+                .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId())
+                .eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo())
+                .eq(StockInventory::getCustomer, stockInventoryDto.getCustomer())
+        );
         if (ObjectUtils.isEmpty(oldStockInventory)) {
             StockInventory newStockInventory = new StockInventory();
             newStockInventory.setProductModelId(stockInventoryDto.getProductModelId());
             newStockInventory.setQualitity(stockInventoryDto.getQualitity());
             newStockInventory.setVersion(1);
             newStockInventory.setRemark(stockInventoryDto.getRemark());
+            newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity());
             newStockInventory.setWarnNum(stockInventoryDto.getWarnNum());
+            newStockInventory.setBatchNo(stockInventoryDto.getBatchNo());
+            newStockInventory.setCustomer(stockInventoryDto.getCustomer());
             stockInventoryMapper.insert(newStockInventory);
         }else {
              stockInventoryMapper.updateAddStockInventory(stockInventoryDto);
@@ -82,23 +110,35 @@
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean subtractStockInventory(StockInventoryDto stockInventoryDto) {
-            //  鏂板鍑哄簱璁板綍
-        StockOutRecordDto stockOutRecordDto = new StockOutRecordDto();
-        stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId());
-        stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType());
-        stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity());
-        stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
-        stockOutRecordDto.setType("0");
-        stockOutRecordService.add(stockOutRecordDto);
-        StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()));
-        if (stockInventoryDto.getQualitity().compareTo( oldStockInventory.getQualitity().subtract(oldStockInventory.getLockedQuantity()))>0) {
-            throw new RuntimeException("搴撳瓨涓嶈冻鏃犳硶鍑哄簱");
+        //  鏂板鍑哄簱璁板綍
+        if (stockInventoryDto.getRecordType() != null) {
+            StockOutRecordDto stockOutRecordDto = new StockOutRecordDto();
+            stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId());
+            stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType());
+            stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity());
+            stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
+            stockOutRecordDto.setBatchNo(stockInventoryDto.getBatchNo());
+            stockOutRecordDto.setCustomer(stockInventoryDto.getCustomer());
+            stockOutRecordDto.setType("0");
+            stockOutRecordService.add(stockOutRecordDto);
         }
+        StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda()
+                .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId())
+                .eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo())
+                .eq(StockInventory::getCustomer, stockInventoryDto.getCustomer())
+        );
         if (ObjectUtils.isEmpty(oldStockInventory)) {
             throw new RuntimeException("浜у搧搴撳瓨涓嶅瓨鍦�");
-        }else {
-            stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto);
         }
+        BigDecimal lockedQty = oldStockInventory.getLockedQuantity();
+        if (lockedQty == null) {
+            lockedQty = BigDecimal.ZERO;
+        }
+        if (stockInventoryDto.getQualitity().compareTo(oldStockInventory.getQualitity().subtract(lockedQty)) > 0) {
+            throw new RuntimeException("搴撳瓨涓嶈冻鏃犳硶鍑哄簱");
+        }
+
+        stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto);
         return true;
     }
 
@@ -121,9 +161,14 @@
                             item.getSpecificationModel().equals(dto.getModel())) {
                         StockInventoryDto stockInventoryDto = new StockInventoryDto();
                         stockInventoryDto.setRecordId(0L);
-                        stockInventoryDto.setRecordType(StockQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode());
+                        stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode());
                         stockInventoryDto.setQualitity(dto.getQualitity());
                         stockInventoryDto.setRemark(dto.getRemark());
+                        stockInventoryDto.setWarnNum(dto.getWarnNum());
+                        if (ObjectUtils.isNotEmpty(dto.getLockedQuantity())&&dto.getLockedQuantity().compareTo(dto.getQualitity())>0) {
+                            throw new RuntimeException("鍐荤粨鏁伴噺涓嶈兘瓒呰繃鏈瀵煎叆鐨勫簱瀛樻暟閲�");
+                        }
+                        stockInventoryDto.setLockedQuantity(dto.getLockedQuantity());
                         stockInventoryDto.setProductModelId(item.getProductModelId());
                         this.addstockInventory(stockInventoryDto);
                         matched = true;
@@ -195,4 +240,216 @@
         stockInventory.setLockedQuantity(stockInventory.getLockedQuantity().subtract(stockInventoryDto.getLockedQuantity()));
         return this.updateById(stockInventory);
     }
+
+    @Override
+    public List<StockInventoryDto> getMaterials(StockInventoryDto stockInventoryDto) {
+        return stockInventoryMapper.getMaterials(stockInventoryDto);
+    }
+
+    @Override
+    public List<ProductTreeDto> getStockInventoryAll(ProductDto productDto) {
+        // 鏌ヨ搴撳瓨鍒楄〃
+        List<StockInventoryDto> stockList = stockInventoryMapper.getStockInventoryAll(productDto);
+
+        if (CollectionUtils.isEmpty(stockList)) {
+            return new ArrayList<>();
+        }
+
+        // 鏋勫缓浜у搧鏍戯紙鍩轰簬浜у搧琛ㄧ殑鐖跺瓙鍏崇郴锛�
+        Map<Long, ProductTreeDto> productNodeMap = buildProductTree(stockList);
+
+        // 灏嗗簱瀛樻暟鎹紙鍨嬪彿->鎵规->瀹㈡埛锛夋寕杞藉埌瀵瑰簲鐨勪骇鍝佽妭鐐逛笅
+        attachStockDataToProduct(productNodeMap, stockList);
+
+        // 杩斿洖鏍硅妭鐐�
+        List<ProductTreeDto> tree = new ArrayList<>();
+        for (ProductTreeDto node : productNodeMap.values()) {
+            if (node.getParentId() == null || node.getParentId() == 0) {
+                tree.add(node);
+            }
+        }
+
+        return tree;
+    }
+
+    /**
+     * 鏋勫缓浜у搧鏍戯紙鑷姩閫掑綊鏌ヨ鎵�鏈夌埗绾э紝鍖呭惈鏍硅妭鐐癸級
+     */
+    private Map<Long, ProductTreeDto> buildProductTree(List<StockInventoryDto> stockList) {
+        // 1. 鏀堕泦鎵�鏈夐渶瑕佸姞杞界殑浜у搧ID
+        Set<Long> needQueryIds = new HashSet<>();
+        for (StockInventoryDto stock : stockList) {
+            if (stock.getProductId() != null) {
+                needQueryIds.add(stock.getProductId());
+            }
+        }
+
+        // 閫掑綊鏌ヨ鎵�鏈夎妭鐐癸紙鐩村埌鏍硅妭鐐癸級
+        Set<Long> allAncestors = getAllAncestorIds(needQueryIds);
+        needQueryIds.addAll(allAncestors);
+
+        // 鎵归噺鏌ヨ鎵�鏈変骇鍝侊紙鍖呭惈瀹屾暣灞傜骇锛�
+        LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>();
+        wrapper.in(Product::getId, needQueryIds);
+        List<Product> products = productMapper.selectList(wrapper);
+
+        // 鏋勫缓鑺傜偣Map
+        Map<Long, ProductTreeDto> nodeMap = new HashMap<>();
+        for (Product product : products) {
+            ProductTreeDto node = new ProductTreeDto();
+            node.setId(product.getId());
+            node.setParentId(product.getParentId());
+            node.setProductName(product.getProductName());
+            node.setLabel(product.getProductName());
+            node.setNodeType("product");
+            node.setChildren(new ArrayList<>());
+            nodeMap.put(product.getId(), node);
+        }
+
+        // 鏋勫缓鐖跺瓙鍏崇郴
+        for (ProductTreeDto node : nodeMap.values()) {
+            Long parentId = node.getParentId();
+            if (parentId != null && parentId != 0 && nodeMap.containsKey(parentId)) {
+                nodeMap.get(parentId).getChildren().add(node);
+            }
+        }
+
+        return nodeMap;
+    }
+
+    /**
+     * 閫掑綊鏌ヨ鎵�鏈変骇鍝佺殑绁栧厛ID锛堢洿鍒版牴鑺傜偣锛�
+     */
+    private Set<Long> getAllAncestorIds(Set<Long> productIds) {
+        Set<Long> ancestorIds = new HashSet<>();
+        Queue<Long> queue = new LinkedList<>(productIds);
+
+        while (!queue.isEmpty()) {
+            Long currentId = queue.poll();
+            Product product = productMapper.selectById(currentId);
+            if (product == null) continue;
+
+            Long parentId = product.getParentId();
+            if (parentId != null && parentId != 0 && !ancestorIds.contains(parentId)) {
+                ancestorIds.add(parentId);
+                queue.add(parentId);
+            }
+        }
+        return ancestorIds;
+    }
+
+    /**
+     * 灏嗗簱瀛樻暟鎹紙鍨嬪彿->鎵规->瀹㈡埛锛夋寕杞藉埌浜у搧鑺傜偣涓�
+     */
+    private void attachStockDataToProduct(Map<Long, ProductTreeDto> productNodeMap,
+                                          List<StockInventoryDto> stockList) {
+        for (StockInventoryDto stock : stockList) {
+            Long productId = stock.getProductId();
+            if (productId == null || !productNodeMap.containsKey(productId)) {
+                continue;
+            }
+
+            ProductTreeDto productNode = productNodeMap.get(productId);
+
+            // 鏋勫缓璇ヤ骇鍝佺殑搴撳瓨鏍戯紙鍨嬪彿 -> 鎵规 -> 瀹㈡埛锛�
+            ProductTreeDto stockTree = buildStockTree(stock);
+
+            // 鍚堝苟鍒颁骇鍝佽妭鐐圭殑 children 涓�
+            mergeStockTree(productNode.getChildren(), stockTree);
+        }
+    }
+
+    /**
+     * 鏋勫缓鍗曚釜搴撳瓨鐨勬爲缁撴瀯锛堝瀷鍙� -> 鎵规 -> 瀹㈡埛锛�
+     */
+    private ProductTreeDto buildStockTree(StockInventoryDto stock) {
+        // 鍨嬪彿鑺傜偣
+        ProductTreeDto modelNode = new ProductTreeDto();
+        modelNode.setModel(stock.getModel());
+        modelNode.setUidNo(stock.getUidNo());
+        modelNode.setUnit(stock.getUnit());
+        modelNode.setProductModelId(stock.getProductModelId());
+        modelNode.setLabel(stock.getModel());
+        modelNode.setNodeType("model");
+        modelNode.setChildren(new ArrayList<>());
+
+        // 鎵规鑺傜偣
+        ProductTreeDto batchNode = new ProductTreeDto();
+        String batchNo = StringUtils.isBlank(stock.getBatchNo()) ? "鏃犳壒娆�" : stock.getBatchNo();
+        batchNode.setBatchNo(batchNo);
+        batchNode.setLabel("鎵规: " + batchNo);
+        batchNode.setNodeType("batch");
+        batchNode.setChildren(new ArrayList<>());
+
+        // 瀹㈡埛鑺傜偣
+        ProductTreeDto customerNode = new ProductTreeDto();
+        String customer = StringUtils.isBlank(stock.getCustomer()) ? "鏃犲鎴�" : stock.getCustomer();
+        customerNode.setCustomer(customer);
+        customerNode.setLabel(customer);
+        customerNode.setNodeType("customer");
+        customerNode.setChildren(new ArrayList<>());
+
+        batchNode.getChildren().add(customerNode);
+        modelNode.getChildren().add(batchNode);
+
+        return modelNode;
+    }
+
+    /**
+     * 鍚堝苟搴撳瓨鏍戝埌浜у搧鑺傜偣鐨� children 涓�
+     */
+    private void mergeStockTree(List<ProductTreeDto> children, ProductTreeDto newStockTree) {
+        if (children == null) {
+            return;
+        }
+
+        // 鏌ユ壘鏄惁宸叉湁鐩稿悓鍨嬪彿鐨勮妭鐐�
+        ProductTreeDto existingModelNode = null;
+        for (ProductTreeDto child : children) {
+            if (child.getNodeType().equals("model") &&
+                    child.getModel() != null &&
+                    child.getModel().equals(newStockTree.getModel())) {
+                existingModelNode = child;
+                break;
+            }
+        }
+
+        if (existingModelNode == null) {
+            // 娌℃湁鐩稿悓鍨嬪彿锛岀洿鎺ユ坊鍔�
+            children.add(newStockTree);
+        } else {
+            // 鏈夌浉鍚屽瀷鍙凤紝鍚堝苟鎵规鑺傜偣
+            ProductTreeDto newBatchNode = newStockTree.getChildren().get(0);
+
+            // 鏌ユ壘鏄惁宸叉湁鐩稿悓鎵规
+            ProductTreeDto existingBatchNode = null;
+            for (ProductTreeDto batchChild : existingModelNode.getChildren()) {
+                if (batchChild.getNodeType().equals("batch") &&
+                        batchChild.getBatchNo() != null &&
+                        batchChild.getBatchNo().equals(newBatchNode.getBatchNo())) {
+                    existingBatchNode = batchChild;
+                    break;
+                }
+            }
+
+            if (existingBatchNode == null) {
+                existingModelNode.getChildren().add(newBatchNode);
+            } else {
+                // 鍚堝苟瀹㈡埛鑺傜偣
+                ProductTreeDto newCustomerNode = newBatchNode.getChildren().get(0);
+                boolean customerExists = false;
+                for (ProductTreeDto customerChild : existingBatchNode.getChildren()) {
+                    if (customerChild.getNodeType().equals("customer") &&
+                            customerChild.getCustomer() != null &&
+                            customerChild.getCustomer().equals(newCustomerNode.getCustomer())) {
+                        customerExists = true;
+                        break;
+                    }
+                }
+                if (!customerExists) {
+                    existingBatchNode.getChildren().add(newCustomerNode);
+                }
+            }
+        }
+    }
 }

--
Gitblit v1.9.3