From 6d3a76f894052209cad136ec9bff6ddcd43fc4e7 Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期一, 20 四月 2026 17:55:48 +0800
Subject: [PATCH] feat: 扫码时做限制,若采购台账已全部质检入库,APP扫码 入库时提示已入库。并且联动质检

---
 src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java |  163 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 153 insertions(+), 10 deletions(-)

diff --git a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
index ac469e8..2afc5dc 100644
--- a/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
+++ b/src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -9,6 +9,7 @@
 import com.ruoyi.basic.mapper.ProductModelMapper;
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
+import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
 import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
 import com.ruoyi.framework.web.domain.R;
 import com.ruoyi.procurementrecord.utils.StockUtils;
@@ -32,6 +33,9 @@
 import com.ruoyi.sales.service.ISalesLedgerProductProcessBindService;
 import com.ruoyi.sales.service.ISalesLedgerProductService;
 import com.ruoyi.stock.mapper.StockInventoryMapper;
+import com.ruoyi.stock.mapper.StockInRecordMapper;
+import com.ruoyi.stock.dto.StockInventoryDto;
+import com.ruoyi.stock.pojo.StockInRecord;
 import com.ruoyi.stock.pojo.StockInventory;
 import lombok.AllArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -89,6 +93,8 @@
 
     private StockUtils stockUtils;
 
+    private StockInRecordMapper stockInRecordMapper;
+
     private final ISalesLedgerProductProcessBindService salesLedgerProductProcessBindService;
 
     @Autowired
@@ -100,7 +106,11 @@
 
     @Override
     public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
-        return salesLedgerProductMapper.selectById(id);
+        SalesLedgerProduct row = salesLedgerProductMapper.selectById(id);
+        if (row != null) {
+            row.fillRemainingQuantity();
+        }
+        return row;
     }
 
     @Override
@@ -189,18 +199,27 @@
             if (item.getFutureTicketsAmount() == null || item.getFutureTicketsAmount().compareTo(BigDecimal.ZERO) == 0) {
                 item.setFutureTicketsAmount(BigDecimal.ZERO);
             }
-            if (item.getApproveStatus() == null || item.getApproveStatus() != 2) {
-                Integer hasSufficientStock = item.getHasSufficientStock();
-                if (hasSufficientStock != null && hasSufficientStock == 0) {
-                    item.setApproveStatus(0);
-                } else {
-                    item.setApproveStatus(1);
-                }
-            }
             BigDecimal returnQuality = finalReturnOrderGroupDtoMap.getOrDefault(item.getId(), BigDecimal.ZERO);
             item.setReturnQuality(returnQuality);
             BigDecimal quantity = item.getQuantity() == null ? BigDecimal.ZERO : item.getQuantity();
-            item.setAvailableQuality(quantity.subtract(returnQuality));
+            BigDecimal shipped = item.getShippedQuantity() == null ? BigDecimal.ZERO : item.getShippedQuantity();
+            BigDecimal available = quantity.subtract(returnQuality).subtract(shipped);
+            item.setAvailableQuality(available.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : available);
+            item.fillRemainingQuantity();
+            if (item.getApproveStatus() == null || item.getApproveStatus() != 2) {
+                BigDecimal remainingShipped = item.getRemainingShippedQuantity() == null ? BigDecimal.ZERO : item.getRemainingShippedQuantity();
+                boolean hasOutbound = shipped.compareTo(BigDecimal.ZERO) > 0;
+                if (hasOutbound && remainingShipped.compareTo(BigDecimal.ZERO) <= 0) {
+                    item.setApproveStatus(0);
+                } else {
+                    Integer hasSufficientStock = item.getHasSufficientStock();
+                    if (hasSufficientStock != null && hasSufficientStock == 0) {
+                        item.setApproveStatus(0);
+                    } else {
+                        item.setApproveStatus(1);
+                    }
+                }
+            }
             ProductModel productModel = finalProductModelMap.get(item.getProductModelId());
             if (productModel != null) {
                 item.setThickness(productModel.getThickness());
@@ -275,14 +294,38 @@
 
         int result;
         Long salesLedgerId = salesLedgerProduct.getSalesLedgerId();
+        salesLedgerProduct.fillRemainingQuantity();
         if (salesLedgerProduct.getId() == null) {
             salesLedgerProduct.setRegisterDate(LocalDateTime.now());
             result = salesLedgerProductMapper.insert(salesLedgerProduct);
             addProductionData(salesLedgerProduct);
         } else {
+            SalesLedgerProduct dbBefore = salesLedgerProductMapper.selectById(salesLedgerProduct.getId());
+            if (dbBefore == null) {
+                throw new RuntimeException("閿�鍞骇鍝佷笉瀛樺湪锛屾棤娉曠紪杈�");
+            }
+            // 涓嶈兘鎶婅鍗曟暟閲忔敼鍒板皬浜庡凡鍙戣揣鏁伴噺锛屽惁鍒欒处瀹炰笉涓�鑷�
+            BigDecimal shipped = dbBefore.getShippedQuantity() == null ? BigDecimal.ZERO : dbBefore.getShippedQuantity();
+            BigDecimal newOrderQty = salesLedgerProduct.getQuantity() == null ? BigDecimal.ZERO : salesLedgerProduct.getQuantity();
+            if (newOrderQty.compareTo(shipped) < 0) {
+                throw new RuntimeException("缂栬緫澶辫触,璁㈠崟鏁伴噺涓嶈兘灏忎簬宸插彂璐ф暟閲�");
+            }
             //鏌ヨ鍘熸湰鐨勪骇鍝佸瀷鍙穒d
             salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity());
             result = salesLedgerProductMapper.updateById(salesLedgerProduct);
+
+            // 鍏佽鈥滃鍏ュ簱鈥濓細褰撹鍗曟暟閲忚涓嬭皟鏃讹紝鍙洖閫�鈥滀笅璋冨樊棰濃�濆搴旂殑鍏ュ簱鏁伴噺
+            // 渚嬶細鍘熻鍗�100锛屽凡鍏ュ簱120锛涙敼涓�50 -> 鍙洖閫�50锛屾渶缁堝凡鍏ュ簱70锛堜笉寮哄帇鍒�50锛�
+            BigDecimal oldOrderQty = dbBefore.getQuantity() == null ? BigDecimal.ZERO : dbBefore.getQuantity();
+            BigDecimal stocked = dbBefore.getStockedQuantity() == null ? BigDecimal.ZERO : dbBefore.getStockedQuantity();
+            BigDecimal reduced = oldOrderQty.subtract(newOrderQty);
+            if (reduced.compareTo(BigDecimal.ZERO) > 0) {
+                BigDecimal rollbackQty = stocked.min(reduced);
+                if (rollbackQty.compareTo(BigDecimal.ZERO) > 0) {
+                    rollbackExcessStockIn(dbBefore, rollbackQty);
+                }
+            }
+
             /*鍒犻櫎瀵瑰簲鐨勭敓浜ф暟鎹苟閲嶆柊鏂板*/
             deleteProductionData(Arrays.asList(salesLedgerProduct.getId()));
             // 鍒犻櫎鐢熶骇鏍哥畻鏁版嵁
@@ -319,8 +362,106 @@
 
             //  娓呯┖閿�鍞骇鍝佺粦瀹氱殑鍔犲伐
             salesLedgerProductProcessBindService.updateProductProcessBind(salesLedgerProduct.getSalesProductProcessList(), salesLedgerProduct.getId());
+
+            // 鏂板/缂栬緫浜у搧鍚庯紝鍒锋柊閿�鍞富鍗曞叆搴撶姸鎬侊紙閬垮厤鍥犳柊澧炴湭鍏ュ簱琛屽鑷寸姸鎬佷笉鍑嗭級
+            refreshSalesLedgerStockStatus(salesLedgerId);
         }
         return result;
+    }
+
+    private void rollbackExcessStockIn(SalesLedgerProduct dbBefore, BigDecimal rollbackQtyTotal) {
+        if (dbBefore == null || rollbackQtyTotal == null || rollbackQtyTotal.compareTo(BigDecimal.ZERO) <= 0) {
+            return;
+        }
+        if (dbBefore.getProductModelId() == null) {
+            throw new RuntimeException("鍥為��鍏ュ簱澶辫触,浜у搧瑙勬牸鏈淮鎶�");
+        }
+        Long productId = dbBefore.getId();
+        //  鍊掑簭鍥為��锛氫紭鍏堝洖閫�鈥滄壂鐮佸叆搴撯�濓紝鍐嶅洖閫�鈥滄墜鍔ㄥ叆搴撯��
+        List<String> recordTypes = Arrays.asList(
+                StockInQualifiedRecordTypeEnum.SALE_SCAN_STOCK_IN.getCode(),
+                StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode()
+        );
+        List<StockInRecord> records = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>()
+                .eq(StockInRecord::getSalesLedgerProductId, productId)
+                .eq(StockInRecord::getType, "0")
+                .in(StockInRecord::getRecordType, recordTypes)
+                .orderByDesc(StockInRecord::getCreateTime));
+        BigDecimal remaining = rollbackQtyTotal;
+        for (StockInRecord r : records) {
+            if (remaining.compareTo(BigDecimal.ZERO) <= 0) {
+                break;
+            }
+            BigDecimal inNum = r.getStockInNum() == null ? BigDecimal.ZERO : r.getStockInNum();
+            if (inNum.compareTo(BigDecimal.ZERO) <= 0) {
+                continue;
+            }
+            BigDecimal rollbackQty = inNum.min(remaining);
+
+            StockInventoryDto stockInventoryDto = new StockInventoryDto();
+            stockInventoryDto.setProductModelId(dbBefore.getProductModelId());
+            stockInventoryDto.setQualitity(rollbackQty);
+            int affectRows = stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto);
+            if (affectRows <= 0) {
+                throw new RuntimeException("鍥為��鍏ュ簱澶辫触,褰撳墠搴撳瓨涓嶈冻,鏃犳硶鎵e洖瓒呭叆搴撴暟閲�");
+            }
+
+            BigDecimal newInNum = inNum.subtract(rollbackQty);
+            if (newInNum.compareTo(BigDecimal.ZERO) <= 0) {
+                stockInRecordMapper.deleteById(r.getId());
+            } else {
+                r.setStockInNum(newInNum);
+                stockInRecordMapper.updateById(r);
+            }
+            remaining = remaining.subtract(rollbackQty);
+        }
+        if (remaining.compareTo(BigDecimal.ZERO) > 0) {
+            throw new RuntimeException("鍥為��鍏ュ簱澶辫触,鏈壘鍒拌冻澶熺殑鍏ュ簱璁板綍鐢ㄤ簬鎵e洖瓒呭叆搴撴暟閲�");
+        }
+
+        //  鍥炲啓浜у搧琛屽凡鍏ュ簱鏁伴噺涓庣姸鎬�
+        SalesLedgerProduct fresh = salesLedgerProductMapper.selectById(dbBefore.getId());
+        if (fresh == null) {
+            return;
+        }
+        BigDecimal newStocked = (fresh.getStockedQuantity() == null ? BigDecimal.ZERO : fresh.getStockedQuantity()).subtract(rollbackQtyTotal);
+        if (newStocked.compareTo(BigDecimal.ZERO) < 0) {
+            newStocked = BigDecimal.ZERO;
+        }
+        BigDecimal orderQty = fresh.getQuantity() == null ? BigDecimal.ZERO : fresh.getQuantity();
+        int stockStatus;
+        if (newStocked.compareTo(BigDecimal.ZERO) <= 0) stockStatus = 0;
+        else if (orderQty.compareTo(BigDecimal.ZERO) > 0 && newStocked.compareTo(orderQty) < 0) stockStatus = 1;
+        else stockStatus = 2;
+        fresh.setStockedQuantity(newStocked);
+        fresh.setProductStockStatus(stockStatus);
+        fresh.fillRemainingQuantity();
+        salesLedgerProductMapper.updateById(fresh);
+    }
+
+    private void refreshSalesLedgerStockStatus(Long salesLedgerId) {
+        if (salesLedgerId == null) {
+            return;
+        }
+        SalesLedger ledger = salesLedgerMapper.selectById(salesLedgerId);
+        if (ledger == null) {
+            return;
+        }
+        List<SalesLedgerProduct> allProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper<SalesLedgerProduct>()
+                .eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId)
+                .eq(SalesLedgerProduct::getType, 1));
+        if (CollectionUtils.isEmpty(allProducts)) {
+            ledger.setStockStatus(0);
+            salesLedgerMapper.updateById(ledger);
+            return;
+        }
+        boolean anyInbound = allProducts.stream().anyMatch(p -> {
+            BigDecimal sq = p.getStockedQuantity();
+            return sq != null && sq.compareTo(BigDecimal.ZERO) > 0;
+        });
+        boolean allFull = allProducts.stream().allMatch(p -> Objects.equals(p.getProductStockStatus(), 2));
+        ledger.setStockStatus(allFull ? 2 : (anyInbound ? 1 : 0));
+        salesLedgerMapper.updateById(ledger);
     }
 
     /**
@@ -497,6 +638,7 @@
             } else {
                 item.setStatusName("鏈畬鎴愪粯娆�");
             }
+            item.fillRemainingQuantity();
         });
         return salesLedgerProductDtoIPage;
     }
@@ -511,6 +653,7 @@
             } else {
                 item.setStatusName("鏈畬鎴愪粯娆�");
             }
+            item.fillRemainingQuantity();
         });
         return salesLedgerProductDtoIPage;
     }

--
Gitblit v1.9.3