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.exception.ServiceException; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.stock.dto.StockInRecordDto; import com.ruoyi.stock.dto.StockInventoryDto; 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 jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.List; /** *

* 不合格库存表 服务实现类 *

* * @author 芯导软件(江苏)有限公司 * @since 2026-01-22 10:17:45 */ @Service @RequiredArgsConstructor public class StockUninventoryServiceImpl extends ServiceImpl implements StockUninventoryService { private final StockUninventoryMapper stockUninventoryMapper; private final StockOutRecordService stockOutRecordService; private final StockInRecordService stockInRecordService; private final ProductModelMapper productModelMapper; private final StockInventoryMapper stockInventoryMapper; @Override public IPage pageStockUninventory(Page page, StockUninventoryDto stockUninventoryDto) { return stockUninventoryMapper.pageStockUninventory(page, stockUninventoryDto); } @Override @Transactional(rollbackFor = Exception.class) public Integer addStockUninventory(StockUninventoryDto stockUninventoryDto) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(StockUninventory::getProductModelId, stockUninventoryDto.getProductModelId()); if (StringUtils.isEmpty(stockUninventoryDto.getBatchNo())) { stockUninventoryDto.setBatchNo(null); wrapper.isNull(StockUninventory::getBatchNo); } else { wrapper.eq(StockUninventory::getBatchNo, stockUninventoryDto.getBatchNo()); } //新增入库记录再添加库存 StockInRecordDto stockInRecordDto = new StockInRecordDto(); stockInRecordDto.setRecordId(stockUninventoryDto.getRecordId()); stockInRecordDto.setRecordType(stockUninventoryDto.getRecordType()); stockInRecordDto.setStockInNum(stockUninventoryDto.getQualitity()); stockInRecordDto.setBatchNo(stockUninventoryDto.getBatchNo()); stockInRecordDto.setProductModelId(stockUninventoryDto.getProductModelId()); stockInRecordDto.setType("1"); stockInRecordService.add(stockInRecordDto); //再进行新增库存数量库存 //先查询库存表中的产品是否存在,不存在新增,存在更新 StockUninventory oldStockUnInventory = stockUninventoryMapper.selectOne(wrapper); if (ObjectUtils.isEmpty(oldStockUnInventory)) { StockUninventory newStockUnInventory = new StockUninventory(); newStockUnInventory.setProductModelId(stockUninventoryDto.getProductModelId()); newStockUnInventory.setQualitity(stockUninventoryDto.getQualitity()); newStockUnInventory.setLockedQuantity(stockUninventoryDto.getLockedQuantity()); newStockUnInventory.setBatchNo(stockUninventoryDto.getBatchNo()); newStockUnInventory.setVersion(1); newStockUnInventory.setRemark(stockUninventoryDto.getRemark()); stockUninventoryMapper.insert(newStockUnInventory); }else { stockUninventoryMapper.updateAddStockUnInventory(stockUninventoryDto); } return 1; } @Override @Transactional(rollbackFor = Exception.class) public Integer subtractStockUninventory(StockUninventoryDto stockUninventoryDto) { // 新增出库记录 StockOutRecordDto stockOutRecordDto = new StockOutRecordDto(); stockOutRecordDto.setRecordId(stockUninventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockUninventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockUninventoryDto.getQualitity()); stockOutRecordDto.setProductModelId(stockUninventoryDto.getProductModelId()); stockOutRecordDto.setBatchNo(stockUninventoryDto.getBatchNo()); stockOutRecordDto.setType("1"); stockOutRecordService.add(stockOutRecordDto); StockUninventory oldStockInventory = stockUninventoryMapper.selectOne(new QueryWrapper().lambda().eq(StockUninventory::getProductModelId, stockUninventoryDto.getProductModelId())); if (ObjectUtils.isEmpty(oldStockInventory)) { throw new RuntimeException("产品库存不存在"); }else { stockUninventoryMapper.updateSubtractStockUnInventory(stockUninventoryDto); } return 1; } @Override @Transactional(rollbackFor = Exception.class) public Integer addStockInRecordOnly(StockUninventoryDto stockUninventoryDto) { StockInRecordDto stockInRecordDto = new StockInRecordDto(); stockInRecordDto.setRecordId(stockUninventoryDto.getRecordId()); stockInRecordDto.setRecordType(stockUninventoryDto.getRecordType()); stockInRecordDto.setStockInNum(stockUninventoryDto.getQualitity()); 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()); stockInRecordService.add(stockInRecordDto); return 1; } @Override @Transactional(rollbackFor = Exception.class) public Integer addStockOutRecordOnly(StockUninventoryDto stockUninventoryDto) { LambdaQueryWrapper eq = new LambdaQueryWrapper<>(); eq.eq(StockUninventory::getProductModelId, stockUninventoryDto.getProductModelId()); if (StringUtils.isEmpty(stockUninventoryDto.getBatchNo())) { eq.isNull(StockUninventory::getBatchNo); } else { eq.eq(StockUninventory::getBatchNo, stockUninventoryDto.getBatchNo()); } StockUninventory stockUninventory = stockUninventoryMapper.selectOne(eq); if (stockUninventory == null) { throw new BaseException("库存记录不存在"); } BigDecimal lockedQty = stockUninventory.getLockedQuantity(); if (lockedQty == null) { lockedQty = BigDecimal.ZERO; } BigDecimal pendingOut = stockUninventoryMapper.selectPendingOutQuantity( stockUninventoryDto.getProductModelId(), stockUninventoryDto.getBatchNo(), "1" ); if (pendingOut == null) { pendingOut = BigDecimal.ZERO; } BigDecimal availableQty = stockUninventory.getQualitity().subtract(lockedQty).subtract(pendingOut); if (stockUninventoryDto.getQualitity().compareTo(availableQty) > 0) { throw new BaseException("申请数量超过可用库存,当前可用库存为:" + availableQty); } StockOutRecordDto stockOutRecordDto = new StockOutRecordDto(); stockOutRecordDto.setRecordId(stockUninventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockUninventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockUninventoryDto.getQualitity()); stockOutRecordDto.setBatchNo(stockUninventoryDto.getBatchNo()); stockOutRecordDto.setProductModelId(stockUninventoryDto.getProductModelId()); stockOutRecordDto.setType("1"); stockOutRecordDto.setRemark(stockUninventoryDto.getRemark()); stockOutRecordService.add(stockOutRecordDto); return 1; } @Override public void exportStockUninventory(HttpServletResponse response, StockUninventoryDto stockUninventoryDto) { List list = stockUninventoryMapper.listStockInventoryExportData(stockUninventoryDto); ExcelUtil util = new ExcelUtil<>(StockUnInventoryExportData.class); util.exportExcel(response,list, "不合格库存信息"); } @Override public Boolean frozenStock(StockInventoryDto stockInventoryDto) { StockUninventory stockUninventory = stockUninventoryMapper.selectById(stockInventoryDto.getId()); if (stockUninventory.getQualitity().compareTo(stockInventoryDto.getLockedQuantity())<0) { throw new RuntimeException("冻结数量不能超过库存数量"); } if (ObjectUtils.isEmpty(stockUninventory.getLockedQuantity())) { stockUninventory.setLockedQuantity(stockInventoryDto.getLockedQuantity()); }else { stockUninventory.setLockedQuantity(stockUninventory.getLockedQuantity().add(stockInventoryDto.getLockedQuantity())); } return this.updateById(stockUninventory); } @Override public Boolean thawStock(StockInventoryDto stockInventoryDto) { StockUninventory stockUninventory = stockUninventoryMapper.selectById(stockInventoryDto.getId()); if (stockUninventory.getLockedQuantity().compareTo(stockInventoryDto.getLockedQuantity())<0) { throw new RuntimeException("解冻数量不能超过冻结数量"); } 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 stockInventoryList = stockInventoryMapper.selectList( Wrappers.lambdaQuery() .select(StockInventory::getBatchNo) .likeRight(StockInventory::getBatchNo, prefix)); for (StockInventory stockInventory : stockInventoryList) { maxSequence = Math.max(maxSequence, parseSequence(stockInventory.getBatchNo(), prefix)); } List stockInRecordList = stockInRecordService.list( Wrappers.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.lambdaQuery().eq(StockInventory::getBatchNo, batchNo)); if (inventoryCount != null && inventoryCount > 0) { return true; } return stockInRecordService.count( Wrappers.lambdaQuery().eq(StockInRecord::getBatchNo, batchNo)) > 0; } }