From 7ab0221edafd81468b37935fd6e8a9f7cebd181f Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期一, 08 六月 2026 15:14:41 +0800
Subject: [PATCH] 销售台账/采购台账,在新增产品数据的时候,增加一个运费单价(非必填),就像那个含税单价一样,当用户填完数量和运费单价之后,可以直接计算出这个产品的总运费

---
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java |  137 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 136 insertions(+), 1 deletions(-)

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 7a70435..0833069 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -27,6 +27,7 @@
 import com.ruoyi.common.enums.ReviewStatusEnum;
 import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
 import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.FreightUtils;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -42,6 +43,7 @@
 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;
@@ -60,6 +62,7 @@
 import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
+import com.ruoyi.stock.dto.StockInRecordDto;
 import com.ruoyi.stock.pojo.StockInRecord;
 import com.ruoyi.stock.service.StockInRecordService;
 import lombok.RequiredArgsConstructor;
@@ -609,7 +612,14 @@
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
         if (!pendingIds.isEmpty()) {
-            stockInRecordService.batchApprove(pendingIds, ReviewStatusEnum.APPROVED.getCode());
+            List<StockInRecordDto.StockInRecordApproveItemDto> approveItems = pendingIds.stream()
+                    .map(id -> {
+                        StockInRecordDto.StockInRecordApproveItemDto item = new StockInRecordDto.StockInRecordApproveItemDto();
+                        item.setId(id);
+                        return item;
+                    })
+                    .collect(Collectors.toList());
+            stockInRecordService.batchApprove(ReviewStatusEnum.APPROVED.getCode(), approveItems);
         }
     }
 
@@ -669,6 +679,7 @@
         // 鎵ц鏇存柊鎿嶄綔
         if (!updateList.isEmpty()) {
             for (SalesLedgerProduct product : updateList) {
+                FreightUtils.fillFreightAmount(product);
                 product.setType(ledgerType);
                 salesLedgerProductMapper.updateById(product);
             }
@@ -676,6 +687,7 @@
         // 鎵ц鎻掑叆鎿嶄綔
         if (!insertList.isEmpty()) {
             for (SalesLedgerProduct salesLedgerProduct : insertList) {
+                FreightUtils.fillFreightAmount(salesLedgerProduct);
                 salesLedgerProduct.setType(ledgerType);
                 Date entryDate = purchaseLedger.getEntryDate();
 
@@ -965,6 +977,7 @@
                 for (PurchaseLedgerProductImportDto salesLedgerProductImportDto : salesLedgerProductImportDtos) {
                     SalesLedgerProduct salesLedgerProduct = new SalesLedgerProduct();
                     BeanUtils.copyProperties(salesLedgerProductImportDto, salesLedgerProduct);
+                    FreightUtils.fillFreightAmount(salesLedgerProduct);
                     salesLedgerProduct.setSalesLedgerId(salesLedger.getId());
                     salesLedgerProduct.setType(2);
                     // 璁$畻涓嶅惈绋庢�讳环
@@ -1051,6 +1064,128 @@
 
     }
 
+    @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("閲囪喘浜у搧涓嶅瓨鍦�");
+            }
+            if (!purchaseLedger.getId().equals(salesLedgerProduct.getSalesLedgerId()) || !Integer.valueOf(2).equals(salesLedgerProduct.getType())) {
+                throw new BaseException("閲囪喘浜у搧涓庨噰璐彴璐︿笉鍖归厤");
+            }
+
+            ProductModel productModel = productModelMapper.selectById(salesLedgerProduct.getProductModelId());
+            if (Boolean.TRUE.equals(salesLedgerProduct.getIsChecked())) {
+                throw new BaseException("浜у搧銆�" + productModel.getModel() + "銆戦渶瑕佽川妫�锛岃璧拌川妫�鍏ュ簱娴佺▼");
+            }
+
+            BigDecimal theoryStockInNum = item.getInboundQuantity();
+            if (theoryStockInNum == null) {
+                theoryStockInNum = salesLedgerProduct.getQuantity();
+            }
+            if (theoryStockInNum == null || theoryStockInNum.compareTo(BigDecimal.ZERO) <= 0) {
+                throw new BaseException("鐞嗚鍏ュ簱鏁伴噺蹇呴』澶т簬0");
+            }
+
+            BigDecimal approvedStockInNum = getApprovedPurchaseStockInNum(
+                    purchaseLedger.getId(),
+                    purchaseLedger.getPurchaseContractNumber(),
+                    salesLedgerProduct.getId(),
+                    salesLedgerProduct.getProductModelId()
+            );
+            BigDecimal remainingStockInNum = salesLedgerProduct.getQuantity().subtract(approvedStockInNum);
+            if (remainingStockInNum.compareTo(BigDecimal.ZERO) <= 0) {
+                throw new BaseException("浜у搧銆�" +  productModel.getModel() + "銆戝凡瀹屾垚鍏ュ簱");
+            }
+            if (theoryStockInNum.compareTo(remainingStockInNum) > 0) {
+                throw new BaseException("浜у搧銆�" +  productModel.getModel() + "銆戠悊璁哄叆搴撴暟閲忎笉鑳藉ぇ浜庡緟鍏ュ簱鏁伴噺" + remainingStockInNum.stripTrailingZeros().toPlainString());
+            }
+
+            Boolean isContainsWater = Boolean.TRUE.equals(item.getIsContainsWater());
+            BigDecimal waterContent = normalizeWaterContent(isContainsWater, item.getWaterContent());
+            BigDecimal actualStockInNum = calculateActualStockInNum(theoryStockInNum, isContainsWater, waterContent);
+            if (actualStockInNum.compareTo(BigDecimal.ZERO) <= 0) {
+                throw new BaseException("瀹為檯鍏ュ簱鏁伴噺蹇呴』澶т簬0");
+            }
+
+            stockUtils.addStockWithBatchNo(
+                    salesLedgerProduct.getProductModelId(),
+                    actualStockInNum,
+                    StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(),
+                    purchaseLedger.getId(),
+                    purchaseLedger.getPurchaseContractNumber() + "-" + salesLedgerProduct.getId(),
+                    isContainsWater,
+                    waterContent,
+                    theoryStockInNum
+            );
+
+            count++;
+        }
+
+        return count;
+    }
+
+    private BigDecimal getApprovedPurchaseStockInNum(Long purchaseLedgerId, String purchaseContractNumber, Long productId, Long productModelId) {
+        if (purchaseLedgerId == null || productId == null || productModelId == null || !StringUtils.hasText(purchaseContractNumber)) {
+            return BigDecimal.ZERO;
+        }
+        List<StockInRecord> stockRecords = findDirectStockRecords(purchaseLedgerId, purchaseContractNumber, productModelId, productId);
+        return stockRecords.stream()
+                .filter(Objects::nonNull)
+                .filter(item -> ReviewStatusEnum.APPROVED.getCode().equals(item.getApprovalStatus()))
+                .map(StockInRecord::getStockInNum)
+                .filter(Objects::nonNull)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+    }
+
+    private BigDecimal normalizeWaterContent(Boolean isContainsWater, BigDecimal waterContent) {
+        if (!Boolean.TRUE.equals(isContainsWater)) {
+            return BigDecimal.ZERO;
+        }
+        if (waterContent == null) {
+            throw new BaseException("鍚按鏃跺繀椤诲~鍐欏惈姘撮噺");
+        }
+        if (waterContent.compareTo(BigDecimal.ZERO) < 0 || waterContent.compareTo(new BigDecimal("100")) >= 0) {
+            throw new BaseException("鍚按閲忓繀椤诲湪0鍒�100涔嬮棿");
+        }
+        return waterContent;
+    }
+
+    private BigDecimal calculateActualStockInNum(BigDecimal theoryStockInNum, Boolean isContainsWater, BigDecimal waterContent) {
+        if (!Boolean.TRUE.equals(isContainsWater)) {
+            return theoryStockInNum;
+        }
+        BigDecimal percent = waterContent.divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP);
+        BigDecimal actualStockInNum = theoryStockInNum.multiply(BigDecimal.ONE.subtract(percent));
+        return actualStockInNum.setScale(4, RoundingMode.HALF_UP);
+    }
+
     /**
      * 涓嬪垝绾垮懡鍚嶈浆椹煎嘲鍛藉悕
      */

--
Gitblit v1.9.3