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; } src/main/java/com/ruoyi/procurementrecord/bean/vo/ShippingProductVo.java
@@ -11,6 +11,9 @@ @Schema(description = "出库单id") private Long id; @Schema(description = "产品规格id") private Long productModelId; @Schema(description = "产品大类") private String productCategory; 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); 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 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; } } 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> 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