From 32e4f30a848e159081986f93d189f0e80fa56a77 Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期五, 29 五月 2026 18:03:52 +0800
Subject: [PATCH] 采购手动入库

---
 src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java                       |   11 ++
 src/main/java/com/ruoyi/stock/pojo/StockInRecord.java                          |    9 ++
 src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java           |    8 ++
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java   |   85 +++++++++++++++++++++
 src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java |   13 +-
 src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java      |    6 +
 doc/万通新型建材.sql                                                                 |    5 +
 src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java  |   10 --
 src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java                |   25 ++++++
 src/main/java/com/ruoyi/purchase/dto/PurchaseStockInDto.java                   |   41 ++++++++++
 src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java      |    4 +
 11 files changed, 202 insertions(+), 15 deletions(-)

diff --git "a/doc/\344\270\207\351\200\232\346\226\260\345\236\213\345\273\272\346\235\220.sql" "b/doc/\344\270\207\351\200\232\346\226\260\345\236\213\345\273\272\346\235\220.sql"
index c5ebe9d..83eb4a3 100644
--- "a/doc/\344\270\207\351\200\232\346\226\260\345\236\213\345\273\272\346\235\220.sql"
+++ "b/doc/\344\270\207\351\200\232\346\226\260\345\236\213\345\273\272\346\235\220.sql"
@@ -50,3 +50,8 @@
 alter table stock_uninventory
     add manufacturer_id bigint not null default 0 comment '鍘傚id',
     add source varchar(255) not null default '' comment '鏉ユ簮';
+
+alter table stock_in_record
+    add is_contains_water boolean default false comment '鏄惁鍚按',
+    add water_content decimal(16, 4) default 0 comment '鍚按閲�',
+    add theory_stock_in_num decimal(16, 4) default 0 comment '鐞嗚鍏ュ簱鏁伴噺';
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
index 2a4f52a..39bf20c 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
@@ -523,16 +523,10 @@
             );
             for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
                 if (salesLedgerProduct.getIsChecked()) {
+                    // 闇�瑕佽川妫�鐨勪骇鍝� -> 鐢熸垚璐ㄦ鍗�
                     qualityInspectHelper.addQualityInspect(purchaseLedger, salesLedgerProduct);
-                } else {
-                    stockUtils.addStockWithBatchNo(
-                            salesLedgerProduct.getProductModelId(),
-                            salesLedgerProduct.getQuantity(),
-                            StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
-                            purchaseLedger.getId(),
-                            purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId()
-                    );
                 }
+                // 涓嶉渶瑕佽川妫�鐨勪骇鍝侊細涓嶅啀鑷姩鍏ュ簱锛屾敼涓烘墜鍔ㄥ叆搴撴寜閽Е鍙�
             }
         } else if ("REJECTED".equals(status)) {
             purchaseLedger.setApprovalStatus(ApprovalStatusEnum.REJECTED.getCode());
diff --git a/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java b/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java
index 8135c3a..696dfdd 100644
--- a/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java
+++ b/src/main/java/com/ruoyi/approve/service/impl/ApproveBusinessStatusService.java
@@ -82,12 +82,13 @@
                 if (Boolean.TRUE.equals(salesLedgerProduct.getIsChecked())) {
                     addQualityInspect(purchaseLedger, salesLedgerProduct);
                 } else {
-                    stockUtils.addStockWithBatchNo(
-                            salesLedgerProduct.getProductModelId(),
-                            salesLedgerProduct.getQuantity(),
-                            StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
-                            purchaseLedger.getId(),
-                            purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId());
+//                    涓嶅啀鑷姩鍏ュ簱锛屾敼涓烘墜鍔ㄥ叆搴撴寜閽Е鍙�
+//                    stockUtils.addStockWithBatchNo(
+//                            salesLedgerProduct.getProductModelId(),
+//                            salesLedgerProduct.getQuantity(),
+//                            StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
+//                            purchaseLedger.getId(),
+//                            purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId());
                 }
             }
         } else if (status.equals(3)) {
diff --git a/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java b/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
index 0beecd2..95537c8 100644
--- a/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
+++ b/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -114,6 +114,31 @@
     }
 
     /**
+     * 鍚堟牸鍏ュ簱甯︽壒娆″彿鍜屽惈姘撮噺淇℃伅
+     * @param productModelId 浜у搧瑙勬牸ID
+     * @param actualStockInNum 瀹為檯鍏ュ簱鏁伴噺
+     * @param recordType 璁板綍绫诲瀷
+     * @param recordId 璁板綍ID
+     * @param batchNo 鎵规鍙�
+     * @param isContainsWater 鏄惁鍚按
+     * @param waterContent 鍚按閲�
+     * @param theoryStockInNum 鐞嗚鍏ュ簱鏁伴噺
+     */
+    public void addStockWithBatchNo(Long productModelId, BigDecimal actualStockInNum, String recordType, Long recordId,
+                                    String batchNo, Boolean isContainsWater, BigDecimal waterContent, BigDecimal theoryStockInNum) {
+        StockInventoryDto stockInventoryDto = new StockInventoryDto();
+        stockInventoryDto.setRecordId(recordId);
+        stockInventoryDto.setRecordType(String.valueOf(recordType));
+        stockInventoryDto.setQualitity(actualStockInNum);
+        stockInventoryDto.setProductModelId(productModelId);
+        stockInventoryDto.setBatchNo(batchNo);
+        stockInventoryDto.setIsContainsWater(isContainsWater);
+        stockInventoryDto.setWaterContent(waterContent);
+        stockInventoryDto.setTheoryStockInNum(theoryStockInNum);
+        stockInventoryService.addStockInRecordOnly(stockInventoryDto);
+    }
+
+    /**
      * 鍚堟牸鍑哄簱
      *
      * @param productModelId
diff --git a/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java b/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
index 537c903..9d5aa75 100644
--- a/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
+++ b/src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -9,6 +9,7 @@
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.framework.web.page.TableDataInfo;
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
+import com.ruoyi.purchase.dto.PurchaseStockInDto;
 import com.ruoyi.purchase.mapper.PurchaseLedgerTemplateMapper;
 import com.ruoyi.purchase.mapper.SalesLedgerProductTemplateMapper;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
@@ -250,4 +251,9 @@
     public AjaxResult createPurchaseNo(@RequestParam Date entryDate) {
         return AjaxResult.success("鐢熸垚鎴愬姛",purchaseLedgerService.getPurchaseNo(entryDate));
     }
+
+    @PostMapping("/manualStockIn")
+    public AjaxResult manualStockIn(@RequestBody PurchaseStockInDto purchaseStockInDto) {
+        return toAjax(purchaseLedgerService.manualStockIn(purchaseStockInDto));
+    }
 }
diff --git a/src/main/java/com/ruoyi/purchase/dto/PurchaseStockInDto.java b/src/main/java/com/ruoyi/purchase/dto/PurchaseStockInDto.java
new file mode 100644
index 0000000..0f4cb5d
--- /dev/null
+++ b/src/main/java/com/ruoyi/purchase/dto/PurchaseStockInDto.java
@@ -0,0 +1,41 @@
+package com.ruoyi.purchase.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 閲囪喘鎵嬪姩鍏ュ簱璇锋眰DTO
+ */
+@Data
+@Schema(description = "閲囪喘鎵嬪姩鍏ュ簱璇锋眰DTO")
+public class PurchaseStockInDto {
+
+    @Schema(description = "閲囪喘鍙拌处ID")
+    private Long purchaseLedgerId;
+
+    @Schema(description = "浜у搧鍏ュ簱鏄庣粏")
+    private List<StockInProductItem> details;
+
+    @Data
+    @Schema(description = "浜у搧鍏ュ簱鏄庣粏椤�")
+    public static class StockInProductItem {
+
+        @Schema(description = "閲囪喘浜у搧ID(sales_ledger_product.id)")
+        private Long id;
+
+        @Schema(description = "鍏ュ簱鏁伴噺(鐞嗚鏁伴噺)")
+        private BigDecimal inboundQuantity;
+
+        @Schema(description = "鏄惁鍚按")
+        private Boolean isContainsWater;
+
+        @Schema(description = "鍚按閲�(%)")
+        private BigDecimal waterContent;
+
+        @Schema(description = "瀹為檯鍏ュ簱鏁伴噺")
+        private BigDecimal actualInboundQuantity;
+    }
+}
diff --git a/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java b/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
index a1f135e..2a80349 100644
--- a/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
+++ b/src/main/java/com/ruoyi/purchase/service/IPurchaseLedgerService.java
@@ -5,6 +5,7 @@
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
+import com.ruoyi.purchase.dto.PurchaseStockInDto;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import org.springframework.web.multipart.MultipartFile;
@@ -45,4 +46,11 @@
     AjaxResult importData(MultipartFile file);
 
     PurchaseLedgerDto getPurchaseByCode(PurchaseLedgerDto purchaseLedgerDto);
+
+    /**
+     * 鎵嬪姩鍏ュ簱
+     * @param purchaseStockInDto 鍏ュ簱璇锋眰DTO
+     * @return 鍏ュ簱缁撴灉
+     */
+    int manualStockIn(PurchaseStockInDto purchaseStockInDto);
 }
diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
index 6008e69..b02ad7c 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -21,6 +21,7 @@
 import com.ruoyi.basic.pojo.ProductModel;
 import com.ruoyi.basic.pojo.SupplierManage;
 import com.ruoyi.basic.utils.FileUtil;
+import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
 import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
@@ -30,11 +31,13 @@
 import com.ruoyi.other.mapper.TempFileMapper;
 import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
 import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
+import com.ruoyi.procurementrecord.utils.StockUtils;
 import com.ruoyi.project.system.domain.SysUser;
 import com.ruoyi.project.system.mapper.SysUserMapper;
 import com.ruoyi.purchase.dto.PurchaseLedgerDto;
 import com.ruoyi.purchase.dto.PurchaseLedgerImportDto;
 import com.ruoyi.purchase.dto.PurchaseLedgerProductImportDto;
+import com.ruoyi.purchase.dto.PurchaseStockInDto;
 import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
 import com.ruoyi.purchase.pojo.PurchaseLedger;
 import com.ruoyi.purchase.service.IPurchaseLedgerService;
@@ -103,6 +106,7 @@
     private final FileUtil fileUtil;
     private final ApprovalInstanceService approvalInstanceService;
     private final ApprovalTemplateMapper approvalTemplateMapper;
+    private final StockUtils stockUtils;
 
     @Override
     public List<PurchaseLedger> selectPurchaseLedgerList(PurchaseLedger purchaseLedger) {
@@ -634,6 +638,87 @@
 
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int manualStockIn(PurchaseStockInDto purchaseStockInDto) {
+        if (purchaseStockInDto == null || purchaseStockInDto.getPurchaseLedgerId() == null) {
+            throw new BaseException("閲囪喘鍙拌处ID涓嶈兘涓虹┖");
+        }
+        if (CollectionUtils.isEmpty(purchaseStockInDto.getDetails())) {
+            throw new BaseException("璇烽�夋嫨鑷冲皯涓�涓骇鍝佽繘琛屽叆搴�");
+        }
+
+        // 鏌ヨ閲囪喘鍙拌处
+        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(purchaseStockInDto.getPurchaseLedgerId());
+        if (purchaseLedger == null) {
+            throw new BaseException("閲囪喘鍙拌处涓嶅瓨鍦�");
+        }
+
+        // 楠岃瘉閲囪喘鍙拌处鐘舵�佹槸鍚︿负宸插鎵�
+        if (!"3".equals(String.valueOf(purchaseLedger.getApprovalStatus()))) {
+            throw new BaseException("鍙湁宸插鎵归�氳繃鐨勯噰璐彴璐︽墠鑳藉叆搴�");
+        }
+
+        int count = 0;
+        for (PurchaseStockInDto.StockInProductItem item : purchaseStockInDto.getDetails()) {
+            if (item.getId() == null) {
+                continue;
+            }
+
+            // 鏌ヨ閲囪喘浜у搧
+            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(item.getId());
+            if (salesLedgerProduct == null) {
+                throw new BaseException("閲囪喘浜у搧涓嶅瓨鍦�");
+            }
+
+            // 鑾峰彇鐞嗚鍏ュ簱鏁伴噺锛堝墠绔紶鍏ョ殑inboundQuantity锛�
+            BigDecimal theoryStockInNum = item.getInboundQuantity();
+            if (theoryStockInNum == null) {
+                theoryStockInNum = salesLedgerProduct.getQuantity();
+            }
+            // 绌哄�煎拰闈炴鏁版牎楠�
+            if (theoryStockInNum == null || theoryStockInNum.compareTo(BigDecimal.ZERO) <= 0) {
+                throw new BaseException("鐞嗚鍏ュ簱鏁伴噺蹇呴』澶т簬0");
+            }
+
+            // 鑾峰彇瀹為檯鍏ュ簱鏁伴噺锛堝墠绔紶鍏ョ殑actualInboundQuantity锛�
+            BigDecimal actualStockInNum = item.getActualInboundQuantity();
+            if (actualStockInNum == null) {
+                actualStockInNum = theoryStockInNum;
+            }
+            // 闈炴鏁版牎楠�
+            if (actualStockInNum.compareTo(BigDecimal.ZERO) <= 0) {
+                throw new BaseException("瀹為檯鍏ュ簱鏁伴噺蹇呴』澶т簬0");
+            }
+
+            // 鑾峰彇鏄惁鍚按鍜屽惈姘撮噺
+            Boolean isContainsWater = item.getIsContainsWater();
+            BigDecimal waterContent = item.getWaterContent();
+            if (waterContent == null) {
+                waterContent = BigDecimal.ZERO;
+            }
+
+            // 璁$畻宸
+            BigDecimal difference = theoryStockInNum.subtract(actualStockInNum);
+
+            // 璋冪敤StockUtils杩涜鍏ュ簱锛堝甫鍚按閲忎俊鎭級
+            stockUtils.addStockWithBatchNo(
+                    salesLedgerProduct.getProductModelId(),
+                    actualStockInNum,
+                    StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
+                    purchaseLedger.getId(),
+                    purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId(),
+                    isContainsWater,
+                    waterContent,
+                    theoryStockInNum
+            );
+
+            count++;
+        }
+
+        return count;
+    }
+
     /**
      * 涓嬪垝绾垮懡鍚嶈浆椹煎嘲鍛藉悕
      */
diff --git a/src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java b/src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
index 9ed2bcb..e6ae203 100644
--- a/src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
+++ b/src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -91,5 +91,14 @@
     private String unQualifiedSource;
 
     @Schema(description = "涓嶅悎鏍煎簱瀛樻潵婧愭枃鏈�")
-       private String unQualifiedSourceText;
+    private String unQualifiedSourceText;
+
+    @Schema(description = "鏄惁鍚按")
+    private Boolean isContainsWater;
+
+    @Schema(description = "鍚按閲�")
+    private BigDecimal waterContent;
+
+    @Schema(description = "鐞嗚鍏ュ簱鏁伴噺")
+    private BigDecimal theoryStockInNum;
 }
diff --git a/src/main/java/com/ruoyi/stock/pojo/StockInRecord.java b/src/main/java/com/ruoyi/stock/pojo/StockInRecord.java
index 2a7d06d..b06df49 100644
--- a/src/main/java/com/ruoyi/stock/pojo/StockInRecord.java
+++ b/src/main/java/com/ruoyi/stock/pojo/StockInRecord.java
@@ -79,4 +79,13 @@
 
     @Schema(description = "鏉ユ簮")
     private String source;
+
+    @Schema(description = "鏄惁鍚按")
+    private Boolean isContainsWater;
+
+    @Schema(description = "鍚按閲�")
+    private BigDecimal waterContent;
+
+    @Schema(description = "鐞嗚鍏ュ簱鏁伴噺")
+    private BigDecimal theoryStockInNum;
 }
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 687837e..44302ec 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -190,6 +190,10 @@
         stockInRecordDto.setWarnNum(stockInventoryDto.getWarnNum());
         stockInRecordDto.setManufacturerId(stockInventoryDto.getManufacturerId());
         stockInRecordDto.setSource(stockInventoryDto.getSource());
+        // 璁剧疆鍚按閲忕浉鍏充俊鎭�
+        stockInRecordDto.setIsContainsWater(stockInventoryDto.getIsContainsWater());
+        stockInRecordDto.setWaterContent(stockInventoryDto.getWaterContent());
+        stockInRecordDto.setTheoryStockInNum(stockInventoryDto.getTheoryStockInNum());
         stockInRecordService.add(stockInRecordDto);
         return true;
     }

--
Gitblit v1.9.3