From bd02d873d7bbcae36a2a1262d921f2fc6b0cce09 Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期三, 06 五月 2026 14:33:41 +0800
Subject: [PATCH] feat(sales): 新增发货台账详情功能并优化库存管理
---
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java | 197 ++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 186 insertions(+), 11 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 c5b4136..d712518 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -1,13 +1,18 @@
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.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.basic.mapper.ProductModelMapper;
+import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
-import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
+import com.ruoyi.common.exception.ServiceException;
+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;
@@ -18,18 +23,21 @@
import com.ruoyi.stock.dto.StockUninventoryDto;
import com.ruoyi.stock.execl.StockInventoryExportData;
import com.ruoyi.stock.mapper.StockInventoryMapper;
+import com.ruoyi.stock.pojo.StockInRecord;
import com.ruoyi.stock.pojo.StockInventory;
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.stock.service.StockInventoryService;
import com.ruoyi.stock.service.StockOutRecordService;
import com.ruoyi.stock.service.StockUninventoryService;
+import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
-import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -52,6 +60,7 @@
private StockOutRecordService stockOutRecordService;
private StockUninventoryService stockUninventoryService;
private SalesLedgerProductMapper salesLedgerProductMapper;
+ private ProductModelMapper productModelMapper;
@Override
public IPage<StockInventoryDto> pagestockInventory(Page page, StockInventoryDto stockInventoryDto) {
return stockInventoryMapper.pagestockInventory(page, stockInventoryDto);
@@ -66,23 +75,34 @@
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean addstockInventory(StockInventoryDto stockInventoryDto) {
+ String batchNo = StringUtils.trim(stockInventoryDto.getBatchNo());
+ if (StringUtils.isEmpty(batchNo)) {
+ batchNo = generateAutoBatchNo(stockInventoryDto.getProductModelId());
+ }
+ stockInventoryDto.setBatchNo(batchNo);
+
+ LambdaQueryWrapper<StockInventory> eq = new QueryWrapper<StockInventory>().lambda()
+ .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId());
+ eq.eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo());
//鏂板鍏ュ簱璁板綍鍐嶆坊鍔犲簱瀛�
StockInRecordDto stockInRecordDto = new StockInRecordDto();
stockInRecordDto.setRecordId(stockInventoryDto.getRecordId());
stockInRecordDto.setRecordType(stockInventoryDto.getRecordType());
stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity());
+ stockInRecordDto.setBatchNo(stockInventoryDto.getBatchNo());
stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
stockInRecordDto.setType("0");
stockInRecordService.add(stockInRecordDto);
//鍐嶈繘琛屾柊澧炲簱瀛樻暟閲忓簱瀛�
//鍏堟煡璇㈠簱瀛樿〃涓殑浜у搧鏄惁瀛樺湪锛屼笉瀛樺湪鏂板锛屽瓨鍦ㄦ洿鏂�
- StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()));
+ StockInventory oldStockInventory = stockInventoryMapper.selectOne(eq);
if (ObjectUtils.isEmpty(oldStockInventory)) {
StockInventory newStockInventory = new StockInventory();
newStockInventory.setProductModelId(stockInventoryDto.getProductModelId());
newStockInventory.setQualitity(stockInventoryDto.getQualitity());
newStockInventory.setVersion(1);
newStockInventory.setRemark(stockInventoryDto.getRemark());
+ newStockInventory.setBatchNo(stockInventoryDto.getBatchNo());
newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity());
newStockInventory.setWarnNum(stockInventoryDto.getWarnNum());
stockInventoryMapper.insert(newStockInventory);
@@ -96,15 +116,26 @@
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean subtractStockInventory(StockInventoryDto stockInventoryDto) {
+ LambdaQueryWrapper<StockInventory> eq = new QueryWrapper<StockInventory>().lambda()
+ .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId());
+ if (StringUtils.isEmpty(stockInventoryDto.getBatchNo())) {
+ eq.isNull(StockInventory::getBatchNo);
+ stockInventoryDto.setBatchNo(null);
+ } else {
+ eq.eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo());
+ }
// 鏂板鍑哄簱璁板綍
StockOutRecordDto stockOutRecordDto = new StockOutRecordDto();
stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId());
stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType());
stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity());
+ stockOutRecordDto.setBatchNo(stockInventoryDto.getBatchNo());
stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
stockOutRecordDto.setType("0");
stockOutRecordService.add(stockOutRecordDto);
- StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()));
+
+
+ StockInventory oldStockInventory = stockInventoryMapper.selectOne(eq);
if (ObjectUtils.isEmpty(oldStockInventory)) {
throw new RuntimeException("浜у搧搴撳瓨涓嶅瓨鍦�");
}
@@ -117,6 +148,145 @@
}
stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto);
+ return true;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean addStockInRecordOnly(StockInventoryDto stockInventoryDto) {
+ String batchNo = StringUtils.trim(stockInventoryDto.getBatchNo());
+ if (StringUtils.isEmpty(batchNo)) {
+ batchNo = generateAutoBatchNo(stockInventoryDto.getProductModelId());
+ }
+ stockInventoryDto.setBatchNo(batchNo);
+
+ StockInRecordDto stockInRecordDto = new StockInRecordDto();
+ stockInRecordDto.setRecordId(stockInventoryDto.getRecordId());
+ stockInRecordDto.setRecordType(stockInventoryDto.getRecordType());
+ stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity());
+ stockInRecordDto.setBatchNo(batchNo);
+ stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
+ stockInRecordDto.setType("0");
+ stockInRecordDto.setRemark(stockInventoryDto.getRemark());
+ stockInRecordService.add(stockInRecordDto);
+ return true;
+ }
+
+ //瑙勫垯鐢熸垚锛�20260424-浜у搧缂栧彿-001
+ private String generateAutoBatchNo(Long productModelId) {
+ if (productModelId == null) {
+ throw new ServiceException("浜у搧瑙勬牸ID涓嶈兘涓虹┖");
+ }
+ ProductModel productModel = productModelMapper.selectById(productModelId);
+ if (productModel == null) {
+ throw new ServiceException("浜у搧瑙勬牸涓嶅瓨鍦紝ID=" + productModelId);
+ }
+ String productCode = StringUtils.trim(productModel.getProductCode());
+ if (StringUtils.isEmpty(productCode)) {
+ throw new ServiceException("浜у搧瑙勬牸鏈淮鎶や骇鍝佺紪鐮侊紝ID=" + productModelId);
+ }
+
+ String dateText = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
+ String prefix = dateText + "-" + productCode + "-";
+ int maxSequence = resolveMaxSequence(prefix);
+ int sequence = maxSequence + 1;
+ while (sequence < 1_000_000) {
+ String batchNo = prefix + String.format("%03d", sequence);
+ if (!isBatchNoExists(batchNo)) {
+ return batchNo;
+ }
+ sequence++;
+ }
+ throw new ServiceException("鎵瑰彿搴忓彿瓒呭嚭鑼冨洿锛岃妫�鏌ユ壒鍙锋暟鎹�");
+ }
+
+ private int resolveMaxSequence(String prefix) {
+ int maxSequence = 0;
+ List<StockInventory> stockInventoryList = stockInventoryMapper.selectList(
+ Wrappers.<StockInventory>lambdaQuery()
+ .select(StockInventory::getBatchNo)
+ .likeRight(StockInventory::getBatchNo, prefix));
+ for (StockInventory stockInventory : stockInventoryList) {
+ maxSequence = Math.max(maxSequence, parseSequence(stockInventory.getBatchNo(), prefix));
+ }
+
+ List<StockInRecord> stockInRecordList = stockInRecordService.list(
+ Wrappers.<StockInRecord>lambdaQuery()
+ .select(StockInRecord::getBatchNo)
+ .likeRight(StockInRecord::getBatchNo, prefix));
+ for (StockInRecord stockInRecord : stockInRecordList) {
+ maxSequence = Math.max(maxSequence, parseSequence(stockInRecord.getBatchNo(), prefix));
+ }
+ return maxSequence;
+ }
+
+ private int parseSequence(String batchNo, String prefix) {
+ if (StringUtils.isEmpty(batchNo) || StringUtils.isEmpty(prefix) || !batchNo.startsWith(prefix)) {
+ return 0;
+ }
+ String sequenceText = batchNo.substring(prefix.length());
+ if (StringUtils.isEmpty(sequenceText) || !sequenceText.matches("\\d+")) {
+ return 0;
+ }
+ try {
+ return Integer.parseInt(sequenceText);
+ } catch (NumberFormatException ignored) {
+ return 0;
+ }
+ }
+
+ private boolean isBatchNoExists(String batchNo) {
+ if (StringUtils.isEmpty(batchNo)) {
+ return false;
+ }
+ Long inventoryCount = stockInventoryMapper.selectCount(
+ Wrappers.<StockInventory>lambdaQuery().eq(StockInventory::getBatchNo, batchNo));
+ if (inventoryCount != null && inventoryCount > 0) {
+ return true;
+ }
+ return stockInRecordService.count(
+ Wrappers.<StockInRecord>lambdaQuery().eq(StockInRecord::getBatchNo, batchNo)) > 0;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean addStockOutRecordOnly(StockInventoryDto stockInventoryDto) {
+ LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<>();
+ eq.eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId());
+ if (StringUtils.isEmpty(stockInventoryDto.getBatchNo())) {
+ eq.isNull(StockInventory::getBatchNo);
+ } else {
+ eq.eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo());
+ }
+ StockInventory stockInventory = stockInventoryMapper.selectOne(eq);
+ if (stockInventory == null) {
+ throw new ServiceException("搴撳瓨璁板綍涓嶅瓨鍦�");
+ }
+ BigDecimal lockedQty = stockInventory.getLockedQuantity();
+ if (lockedQty == null) {
+ lockedQty = BigDecimal.ZERO;
+ }
+ BigDecimal pendingOut = stockInventoryMapper.selectPendingOutQuantity(
+ stockInventoryDto.getProductModelId(),
+ stockInventoryDto.getBatchNo(),
+ "0"
+ );
+ if (pendingOut == null) {
+ pendingOut = BigDecimal.ZERO;
+ }
+ BigDecimal availableQty = stockInventory.getQualitity().subtract(lockedQty).subtract(pendingOut);
+ if (stockInventoryDto.getQualitity().compareTo(availableQty) > 0) {
+ throw new ServiceException("鐢宠鏁伴噺瓒呰繃鍙敤搴撳瓨锛屽綋鍓嶅彲鐢ㄥ簱瀛樹负锛�" + availableQty);
+ }
+ StockOutRecordDto stockOutRecordDto = new StockOutRecordDto();
+ stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId());
+ stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType());
+ stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity());
+ stockOutRecordDto.setBatchNo(stockInventoryDto.getBatchNo());
+ stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
+ stockOutRecordDto.setType("0");
+ stockOutRecordDto.setRemark(stockInventoryDto.getRemark());
+ stockOutRecordService.add(stockOutRecordDto);
return true;
}
@@ -145,7 +315,7 @@
// 鏋勫缓鏌ユ壘閿�
String key = dto.getProductName() + "|" + dto.getModel();
SalesLedgerProduct matchedProduct = productMap.get(key);
-
+
if (matchedProduct != null) {
// 澶勭悊鍚堟牸搴撳瓨
if (dto.getQualifiedQuantity() != null && dto.getQualifiedQuantity().compareTo(BigDecimal.ZERO) > 0) {
@@ -155,7 +325,7 @@
stockInventoryDto.setQualitity(dto.getQualifiedQuantity());
stockInventoryDto.setRemark(dto.getRemark());
stockInventoryDto.setWarnNum(dto.getWarnNum());
-
+
// 楠岃瘉鍚堟牸鍐荤粨鏁伴噺
if (ObjectUtils.isNotEmpty(dto.getQualifiedLockedQuantity())) {
if (dto.getQualifiedLockedQuantity().compareTo(dto.getQualifiedQuantity()) > 0) {
@@ -165,7 +335,7 @@
} else {
stockInventoryDto.setLockedQuantity(BigDecimal.ZERO);
}
-
+
stockInventoryDto.setProductModelId(matchedProduct.getProductModelId());
this.addstockInventory(stockInventoryDto);
successCount++;
@@ -178,7 +348,7 @@
stockUninventoryDto.setRecordType(StockInUnQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode());
stockUninventoryDto.setQualitity(dto.getUnQualifiedQuantity());
stockUninventoryDto.setRemark(dto.getRemark());
-
+
// 楠岃瘉涓嶅悎鏍煎喕缁撴暟閲�
if (ObjectUtils.isNotEmpty(dto.getUnQualifiedLockedQuantity())) {
if (dto.getUnQualifiedLockedQuantity().compareTo(dto.getUnQualifiedQuantity()) > 0) {
@@ -199,7 +369,7 @@
unmatchedRecords.add(unmatchedRecord);
}
}
-
+
// 鏋勫缓杩斿洖淇℃伅
StringBuilder message = new StringBuilder();
if (!unmatchedRecords.isEmpty()) {
@@ -209,7 +379,7 @@
}
return R.ok(message.toString());
}
-
+
return R.ok("瀵煎叆鎴愬姛锛屽叡澶勭悊 " + successCount + " 鏉¤褰�");
} catch (Exception e) {
log.error("瀵煎叆搴撳瓨澶辫触", e);
@@ -259,4 +429,9 @@
stockInventory.setLockedQuantity(stockInventory.getLockedQuantity().subtract(stockInventoryDto.getLockedQuantity()));
return this.updateById(stockInventory);
}
-}
\ No newline at end of file
+
+ @Override
+ public List<StockInventory> getByModelId(Long modelId) {
+ return stockInventoryMapper.getByModelId(modelId);
+ }
+}
--
Gitblit v1.9.3