package com.ruoyi.stock.service.impl; 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.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.domain.R; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.pojo.SalesLedgerProduct; 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.StockInventoryExportData; import com.ruoyi.stock.mapper.StockInventoryMapper; 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 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.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** *

* 库存表 服务实现类 *

* * @author 芯导软件(江苏)有限公司 * @since 2026-01-21 04:16:36 */ @Service @AllArgsConstructor public class StockInventoryServiceImpl extends ServiceImpl implements StockInventoryService { private StockInventoryMapper stockInventoryMapper; private StockInRecordService stockInRecordService; private StockOutRecordService stockOutRecordService; private StockUninventoryService stockUninventoryService; private SalesLedgerProductMapper salesLedgerProductMapper; @Override public IPage pagestockInventory(Page page, StockInventoryDto stockInventoryDto) { return stockInventoryMapper.pagestockInventory(page, stockInventoryDto); } @Override public IPage pageListCombinedStockInventory(Page page, StockInventoryDto stockInventoryDto) { return stockInventoryMapper.pageListCombinedStockInventory(page, stockInventoryDto); } //入库调用 @Override @Transactional(rollbackFor = Exception.class) public Boolean addstockInventory(StockInventoryDto stockInventoryDto) { //新增入库记录再添加库存 // 更新订单产品入库状态(仅当传入了产品行ID时) if (stockInventoryDto.getSalesLedgerProductId() != null) { SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(stockInventoryDto.getSalesLedgerProductId()); if (salesLedgerProduct == null) { throw new ServiceException("入库失败,销售产品不存在"); } salesLedgerProduct.setProductStockStatus(1); salesLedgerProductMapper.updateById(salesLedgerProduct); } StockInRecordDto stockInRecordDto = new StockInRecordDto(); stockInRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockInRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity()); stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockInRecordDto.setType("0"); stockInRecordDto.setSalesLedgerId(stockInventoryDto.getSalesLedgerId()); stockInRecordDto.setSalesLedgerProductId(stockInventoryDto.getSalesLedgerProductId()); stockInRecordService.add(stockInRecordDto); //再进行新增库存数量库存 //先查询库存表中的产品是否存在,不存在新增,存在更新 List stockInventories = stockInventoryMapper.selectList(new QueryWrapper().lambda() .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()) .orderByDesc(StockInventory::getId)); StockInventory oldStockInventory = (stockInventories == null || stockInventories.isEmpty()) ? null : stockInventories.get(0); if (ObjectUtils.isEmpty(oldStockInventory)) { StockInventory newStockInventory = new StockInventory(); newStockInventory.setProductModelId(stockInventoryDto.getProductModelId()); newStockInventory.setQualitity(stockInventoryDto.getQualitity()); newStockInventory.setVersion(1); newStockInventory.setRemark(stockInventoryDto.getRemark()); newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity()); newStockInventory.setWarnNum(stockInventoryDto.getWarnNum()); stockInventoryMapper.insert(newStockInventory); } else { stockInventoryMapper.updateAddStockInventory(stockInventoryDto); } return true; } //出库调用 @Override @Transactional(rollbackFor = Exception.class) public Boolean subtractStockInventory(StockInventoryDto stockInventoryDto) { // 新增出库记录 StockOutRecordDto stockOutRecordDto = new StockOutRecordDto(); stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity()); stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockOutRecordDto.setType("0"); stockOutRecordDto.setSalesLedgerId(stockInventoryDto.getSalesLedgerId()); stockOutRecordDto.setSalesLedgerProductId(stockInventoryDto.getSalesLedgerProductId()); stockOutRecordService.add(stockOutRecordDto); List stockInventories = stockInventoryMapper.selectList(new QueryWrapper().lambda() .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()) .orderByDesc(StockInventory::getId)); StockInventory oldStockInventory = (stockInventories == null || stockInventories.isEmpty()) ? null : stockInventories.get(0); if (ObjectUtils.isEmpty(oldStockInventory)) { throw new RuntimeException("产品库存不存在"); } BigDecimal lockedQty = oldStockInventory.getLockedQuantity(); if (lockedQty == null) { lockedQty = BigDecimal.ZERO; } if (stockInventoryDto.getQualitity().compareTo(oldStockInventory.getQualitity().subtract(lockedQty)) > 0) { throw new RuntimeException("库存不足无法出库"); } int affectRows = stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto); if (affectRows <= 0) { throw new RuntimeException("库存不足无法出库"); } return true; } @Override @Transactional(rollbackFor = Exception.class) public R importStockInventory(MultipartFile file) { try { // 查询所有的产品 List salesLedgerProducts = salesLedgerProductMapper.selectProduct(); Map productMap = new HashMap<>(); for (SalesLedgerProduct product : salesLedgerProducts) { // 使用产品名称 + 规格型号 + 厚度作为键 String key = buildProductKey(product.getProductCategory(), product.getSpecificationModel(), product.getThickness()); productMap.put(key, product); } ExcelUtil util = new ExcelUtil(StockInventoryExportData.class); List list = util.importExcel(file.getInputStream()); // 记录未找到匹配项的数据 List unmatchedRecords = new ArrayList<>(); int successCount = 0; for (StockInventoryExportData dto : list) { // 构建查找键 String key = buildProductKey(dto.getProductName(), dto.getModel(), dto.getThickness()); SalesLedgerProduct matchedProduct = productMap.get(key); if (matchedProduct != null) { // 处理合格库存 if (dto.getQualifiedQuantity() != null && dto.getQualifiedQuantity().compareTo(BigDecimal.ZERO) > 0) { StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setRecordId(0L); stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode()); stockInventoryDto.setQualitity(dto.getQualifiedQuantity()); stockInventoryDto.setRemark(dto.getRemark()); stockInventoryDto.setWarnNum(dto.getWarnNum()); // 验证合格冻结数量 if (ObjectUtils.isNotEmpty(dto.getQualifiedLockedQuantity())) { if (dto.getQualifiedLockedQuantity().compareTo(dto.getQualifiedQuantity()) > 0) { throw new ServiceException("合格冻结数量不能超过本次导入的合格库存数量"); } stockInventoryDto.setLockedQuantity(dto.getQualifiedLockedQuantity()); } else { stockInventoryDto.setLockedQuantity(BigDecimal.ZERO); } stockInventoryDto.setProductModelId(matchedProduct.getProductModelId()); this.addstockInventory(stockInventoryDto); successCount++; } // 处理不合格库存 if (dto.getUnQualifiedQuantity() != null && dto.getUnQualifiedQuantity().compareTo(BigDecimal.ZERO) > 0) { StockUninventoryDto stockUninventoryDto = new StockUninventoryDto(); stockUninventoryDto.setRecordId(0L); 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) { throw new ServiceException("不合格冻结数量不能超过本次导入的不合格库存数量"); } stockUninventoryDto.setLockedQuantity(dto.getUnQualifiedLockedQuantity()); } else { stockUninventoryDto.setLockedQuantity(BigDecimal.ZERO); } stockUninventoryDto.setProductModelId(matchedProduct.getProductModelId()); stockUninventoryService.addStockUninventory(stockUninventoryDto); successCount++; } } else { // 记录未匹配的产品 String unmatchedRecord = "产品名称:" + dto.getProductName() + ",型号:" + dto.getModel() + ",厚度:" + normalizeThickness(dto.getThickness()); unmatchedRecords.add(unmatchedRecord); } } // 构建返回信息 StringBuilder message = new StringBuilder(); if (!unmatchedRecords.isEmpty()) { message.append("导入成功 " + successCount + " 条记录,以下产品未找到匹配项:\n"); for (String record : unmatchedRecords) { message.append(record).append("\n"); } return R.ok(message.toString()); } return R.ok("导入成功,共处理 " + successCount + " 条记录"); } catch (Exception e) { log.error("导入库存失败", e); return R.fail("导入失败:" + e.getMessage()); } } @Override public void exportStockInventory(HttpServletResponse response, StockInventoryDto stockInventoryDto) { List list = stockInventoryMapper.listStockInventoryExportData(stockInventoryDto); ExcelUtil util = new ExcelUtil<>(StockInventoryExportData.class); util.exportExcel(response, list, "库存信息"); } @Override public IPage stockInventoryPage(StockInventoryDto stockInventoryDto, Page page) { return stockInventoryMapper.stockInventoryPage(stockInventoryDto, page); } @Override public IPage stockInAndOutRecord(StockInventoryDto stockInventoryDto, Page page) { return stockInventoryMapper.stockInAndOutRecord(stockInventoryDto, page); } @Override public Boolean frozenStock(StockInventoryDto stockInventoryDto) { StockInventory stockInventory = stockInventoryMapper.selectById(stockInventoryDto.getId()); if (ObjectUtils.isEmpty(stockInventory)) { throw new ServiceException("库存记录不存在"); } if (ObjectUtils.isEmpty(stockInventoryDto.getLockedQuantity()) || stockInventoryDto.getLockedQuantity().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("冻结数量必须大于0"); } BigDecimal totalQty = ObjectUtils.isEmpty(stockInventory.getQualitity()) ? BigDecimal.ZERO : stockInventory.getQualitity(); BigDecimal currentLockedQty = ObjectUtils.isEmpty(stockInventory.getLockedQuantity()) ? BigDecimal.ZERO : stockInventory.getLockedQuantity(); BigDecimal availableQty = totalQty.subtract(currentLockedQty); if (stockInventoryDto.getLockedQuantity().compareTo(availableQty) > 0) { throw new ServiceException("冻结数量不能超过可冻结库存数量"); } stockInventory.setLockedQuantity(currentLockedQty.add(stockInventoryDto.getLockedQuantity())); return this.updateById(stockInventory); } @Override public Boolean thawStock(StockInventoryDto stockInventoryDto) { StockInventory stockInventory = stockInventoryMapper.selectById(stockInventoryDto.getId()); if (ObjectUtils.isEmpty(stockInventory)) { throw new ServiceException("库存记录不存在"); } if (ObjectUtils.isEmpty(stockInventoryDto.getLockedQuantity()) || stockInventoryDto.getLockedQuantity().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("解冻数量必须大于0"); } BigDecimal currentLockedQty = ObjectUtils.isEmpty(stockInventory.getLockedQuantity()) ? BigDecimal.ZERO : stockInventory.getLockedQuantity(); if (currentLockedQty.compareTo(stockInventoryDto.getLockedQuantity()) < 0) { throw new ServiceException("解冻数量不能超过冻结数量"); } stockInventory.setLockedQuantity(currentLockedQty.subtract(stockInventoryDto.getLockedQuantity())); return this.updateById(stockInventory); } private String buildProductKey(String productName, String model, BigDecimal thickness) { String safeProductName = productName == null ? "" : productName.trim(); String safeModel = model == null ? "" : model.trim(); return safeProductName + "|" + safeModel + "|" + normalizeThickness(thickness); } private String normalizeThickness(BigDecimal thickness) { if (thickness == null) { return ""; } return thickness.stripTrailingZeros().toPlainString(); } }