From 9468068e746f25fc2d4bd618b9a07166f269e32a Mon Sep 17 00:00:00 2001
From: zss <zss@example.com>
Date: 星期二, 12 五月 2026 17:32:18 +0800
Subject: [PATCH] feat(stock): 不合格库存批次号自动生成及使用
---
src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java | 12 +--
src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java | 3 +
src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java | 97 ++++++++++++++++++++++++++++++-
src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnSaleProductDto.java | 11 +++
src/main/resources/mapper/sales/ShippingInfoMapper.xml | 2
src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java | 18 ++++++
src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml | 9 ++
7 files changed, 139 insertions(+), 13 deletions(-)
diff --git a/src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnSaleProductDto.java b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnSaleProductDto.java
index c312d8a..6cfae1b 100644
--- a/src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnSaleProductDto.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/dto/ReturnSaleProductDto.java
@@ -1,6 +1,7 @@
package com.ruoyi.procurementrecord.bean.dto;
import com.ruoyi.procurementrecord.pojo.ReturnSaleProduct;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@@ -17,6 +18,7 @@
//鏈��璐ф暟閲�
private BigDecimal unQuantity;
+ //鎬婚��璐ф暟閲�
private BigDecimal totalReturnNum;
// 閫�璐ф�讳环
@@ -24,4 +26,13 @@
// 閫�璐ф�讳环
private BigDecimal taxInclusiveUnitPrice;
+
+ @Schema(description = "鍑哄簱鍗曞彿")
+ private String outboundBatches;
+
+ @Schema(description = "鎵规鍙�")
+ private String batchNo;
+
+ @Schema(description = "鍙戣揣鍑哄簱鏁伴噺")
+ private BigDecimal stockOutNum;
}
diff --git a/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java b/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java
index b2e2626..9f87aef 100644
--- a/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java
+++ b/src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java
@@ -11,6 +11,9 @@
@Schema(description = "鍑哄簱鍗昳d")
private Long id;
+ @Schema(description = "浜у搧瑙勬牸id")
+ private Long productModelId;
+
@Schema(description = "浜у搧澶х被")
private String productCategory;
diff --git a/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java b/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
index f1e3185..dd250cf 100644
--- a/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
+++ b/src/main/java/com/ruoyi/procurementrecord/service/impl/ReturnManagementServiceImpl.java
@@ -21,7 +21,6 @@
import com.ruoyi.procurementrecord.service.ReturnSaleProductService;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
-import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.service.ShippingInfoService;
import lombok.RequiredArgsConstructor;
@@ -91,8 +90,6 @@
@Override
public ShippingInfoVo getReturnManagementDtoByShippingIdId(Long shippingId) {
ShippingInfo byId = shippingInfoService.getById(shippingId);
- SalesLedger salesLedger = salesLedgerMapper.selectById(byId.getSalesLedgerId());
-// BeanUtils.copyProperties(salesLedger, salesLedgerDto);
ShippingInfoVo shippingInfoVo = new ShippingInfoVo();
shippingInfoVo.setShippingInfo(byId);
List<ShippingProductVo> shippingProductVos = shippingInfoService.getReturnManagementDtoById(byId.getId());
@@ -105,6 +102,7 @@
ReturnManagement byId = this.getById(returnManagementId);
List<ReturnSaleProductDto> list = returnSaleProductService.listReturnSaleProduct(returnManagementId);
byId.setStatus(1);
+ byId.setSettler(SecurityUtils.getLoginUser().getNickName());
updateById(byId);
SalesRefundAmountOrderDto salesRefundAmountOrder = new SalesRefundAmountOrderDto();
salesRefundAmountOrder.setReturnManagementId(returnManagementId);
@@ -117,11 +115,11 @@
salesRefundAmountOrder.setRefundedAmount(new BigDecimal(0));
// 鏄惁鏈夎川閲忛棶棰�
if (returnSaleProduct.getIsQuality() == 1) {
- // 鏈夎川閲忛棶棰橈紝鍏ヤ笉鍚堟牸搴�
- stockUtils.addUnStock(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_UNSTOCK_IN.getCode(),returnSaleProduct.getId());
+ // 鏈夎川閲忛棶棰橈紝鍏ヤ笉鍚堟牸搴�(甯︽壒娆�)
+ stockUtils.addUnStockWithBatchNo(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_UNSTOCK_IN.getCode(),returnSaleProduct.getId(),returnSaleProduct.getBatchNo());
}else{
- // 鏃犺川閲忛棶棰橈紝鍏ュ悎鏍煎簱
- stockUtils.addStock(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_HE_IN.getCode(),returnSaleProduct.getId());
+ // 鏃犺川閲忛棶棰橈紝鍏ュ悎鏍煎簱(甯︽壒娆�)
+ stockUtils.addStockWithBatchNo(returnSaleProduct.getProductModelId(),returnSaleProduct.getNum(), StockInQualifiedRecordTypeEnum.RETURN_HE_IN.getCode(),returnSaleProduct.getId(),returnSaleProduct.getBatchNo());
}
}
salesRefundAmountOrder.setRefundAmount(bigDecimal);
diff --git a/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java b/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
index b7e0478..8a6925e 100644
--- a/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
+++ b/src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -49,6 +49,24 @@
}
/**
+ * 涓嶅悎鏍煎叆搴撳甫鎵规鍙�
+ *
+ * @param productModelId
+ * @param quantity
+ * @param recordType
+ * @param recordId
+ */
+ public void addUnStockWithBatchNo(Long productModelId, BigDecimal quantity, String recordType, Long recordId, String batchNo) {
+ StockUninventoryDto stockUninventoryDto = new StockUninventoryDto();
+ stockUninventoryDto.setRecordId(recordId);
+ stockUninventoryDto.setRecordType(String.valueOf(recordType));
+ stockUninventoryDto.setQualitity(quantity);
+ stockUninventoryDto.setProductModelId(productModelId);
+ stockUninventoryDto.setBatchNo(batchNo);
+ stockUninventoryService.addStockInRecordOnly(stockUninventoryDto);
+ }
+
+ /**
* 涓嶅悎鏍煎嚭搴�
*
* @param productModelId
diff --git a/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java b/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
index 4835b09..4c7d157 100644
--- a/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
+++ b/src/main/java/com/ruoyi/stock/service/impl/StockUninventoryServiceImpl.java
@@ -4,8 +4,12 @@
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.exception.ServiceException;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -14,21 +18,22 @@
import com.ruoyi.stock.dto.StockOutRecordDto;
import com.ruoyi.stock.dto.StockUninventoryDto;
import com.ruoyi.stock.execl.StockUnInventoryExportData;
+import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.mapper.StockUninventoryMapper;
+import com.ruoyi.stock.pojo.StockInRecord;
import com.ruoyi.stock.pojo.StockInventory;
import com.ruoyi.stock.pojo.StockUninventory;
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.stock.service.StockOutRecordService;
import com.ruoyi.stock.service.StockUninventoryService;
-import lombok.AllArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import jakarta.servlet.http.HttpServletResponse;
-
import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
import java.util.List;
/**
@@ -47,6 +52,8 @@
private final StockUninventoryMapper stockUninventoryMapper;
private final StockOutRecordService stockOutRecordService;
private final StockInRecordService stockInRecordService;
+ private final ProductModelMapper productModelMapper;
+ private final StockInventoryMapper stockInventoryMapper;
@Override
public IPage<StockUninventoryDto> pageStockUninventory(Page page, StockUninventoryDto stockUninventoryDto) {
@@ -120,7 +127,11 @@
stockInRecordDto.setRecordId(stockUninventoryDto.getRecordId());
stockInRecordDto.setRecordType(stockUninventoryDto.getRecordType());
stockInRecordDto.setStockInNum(stockUninventoryDto.getQualitity());
- stockInRecordDto.setBatchNo(stockUninventoryDto.getBatchNo());
+ String batchNo = StringUtils.trim(stockUninventoryDto.getBatchNo());
+ if (StringUtils.isEmpty(batchNo)) {
+ batchNo = generateAutoBatchNo(stockUninventoryDto.getProductModelId());
+ }
+ stockInRecordDto.setBatchNo(batchNo);
stockInRecordDto.setProductModelId(stockUninventoryDto.getProductModelId());
stockInRecordDto.setType("1");
stockInRecordDto.setRemark(stockUninventoryDto.getRemark());
@@ -200,4 +211,80 @@
stockUninventory.setLockedQuantity(stockUninventory.getLockedQuantity().subtract(stockInventoryDto.getLockedQuantity()));
return this.updateById(stockUninventory);
}
+
+ //瑙勫垯鐢熸垚锛�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;
+ }
}
diff --git a/src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml b/src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml
index 656a250..616e8a7 100644
--- a/src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml
+++ b/src/main/resources/mapper/procurementrecord/ReturnSaleProductMapper.xml
@@ -16,6 +16,9 @@
pm.model as model,
pm.unit as unit,
rsp.*,
+ sor.outbound_batches,
+ sor.stock_out_num,
+ sor.batch_no,
GREATEST(sor.stock_out_num - COALESCE(rsp.num, 0), 0) AS un_quantity,
COALESCE(rs.total_return_num, 0) AS total_return_num
FROM return_sale_product rsp
@@ -34,11 +37,15 @@
where rm.id =#{returnManagementId}
</select>
<select id="listReturnSaleProduct" resultType="com.ruoyi.procurementrecord.bean.dto.ReturnSaleProductDto">
- select rsp.*,slp.tax_inclusive_unit_price ,slp.tax_inclusive_total_price*rsp.num as price
+ select rsp.*,
+ sor.batch_no,
+ slp.tax_inclusive_unit_price ,
+ slp.tax_inclusive_total_price*rsp.num as price
from return_sale_product rsp
LEFT JOIN return_management rm ON rm.id = rsp.return_management_id
LEFT JOIN shipping_info si ON si.id = rm.shipping_id
LEFT JOIN sales_ledger_product slp ON si.sales_ledger_product_id = slp.id and slp.type = 1
+ LEFT JOIN stock_out_record sor ON rsp.stock_out_record_id = sor.id
where rsp.return_management_id = #{returnManagementId}
</select>
diff --git a/src/main/resources/mapper/sales/ShippingInfoMapper.xml b/src/main/resources/mapper/sales/ShippingInfoMapper.xml
index aa73dac..762c2d4 100644
--- a/src/main/resources/mapper/sales/ShippingInfoMapper.xml
+++ b/src/main/resources/mapper/sales/ShippingInfoMapper.xml
@@ -72,6 +72,7 @@
slp.product_category,
slp.specification_model,
slp.unit,
+ slp.product_model_id,
sor.outbound_batches,
sor.stock_out_num,
sor.batch_no,
@@ -97,6 +98,7 @@
si.id = #{shippingId}
</if>
</where>
+ order by sor.id
</select>
<select id="getShippingInfoByCustomerName" resultType="com.ruoyi.sales.pojo.ShippingInfo">
select * from shipping_info si
--
Gitblit v1.9.3