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.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.equipmentenergyconsumption.mapper.ElectricityConsumptionAreaMapper; import com.ruoyi.framework.web.domain.R; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.stock.dto.StockInRecordDto; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.dto.StockOutRecordDto; 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.word.WeighbridgeDocGenerator; import lombok.RequiredArgsConstructor; import org.springframework.aop.framework.AopContext; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; 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.math.RoundingMode; import java.util.List; import java.util.Optional; /** *

* 库存表 服务实现类 *

* * @author 芯导软件(江苏)有限公司 * @since 2026-01-21 04:16:36 */ @Service @RequiredArgsConstructor(onConstructor_ = @Autowired) public class StockInventoryServiceImpl extends ServiceImpl implements StockInventoryService { private final StockInventoryMapper stockInventoryMapper; private final StockInRecordService stockInRecordService; private final StockOutRecordService stockOutRecordService; private final SalesLedgerProductMapper salesLedgerProductMapper; private final WeighbridgeDocGenerator weighbridgeDocGenerator; private final ProductMapper productMapper; private final ProductModelMapper productModelMapper; private final ElectricityConsumptionAreaMapper electricityConsumptionAreaMapper; @Override public IPage pagestockInventory(Page page, StockInventoryDto stockInventoryDto) { return stockInventoryMapper.pagestockInventory(page, stockInventoryDto); } //入库调用 @Override @Transactional(rollbackFor = Exception.class) public Boolean addstockInventory(StockInventoryDto stockInventoryDto) { // 1. 创建入库记录 StockInRecordDto stockInRecordDto = new StockInRecordDto(); stockInRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockInRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockInRecordDto.setWeighingOperator(stockInventoryDto.getWeighingOperator()); stockInRecordDto.setUnit(stockInventoryDto.getUnit()); Long modelId; if (stockInventoryDto.getProductId() != null) { stockInRecordDto.setProductId(stockInventoryDto.getProductId()); stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); modelId = stockInventoryDto.getProductModelId(); } else { Product parent = productMapper.selectOne(new LambdaQueryWrapper().eq(Product::getProductName, "原材料").last("limit 1")); if (parent == null) { throw new RuntimeException("原材料分类不存在"); } Product product; Product existingProduct = productMapper.selectOne( new LambdaQueryWrapper() .eq(Product::getParentId, parent.getId()) .eq(Product::getProductName, stockInventoryDto.getProductName()) ); if (existingProduct != null) { // 已存在 product = existingProduct; } else { // 不存在 Product newProduct = new Product(); newProduct.setParentId(parent.getId()); newProduct.setProductName(stockInventoryDto.getProductName()); productMapper.insert(newProduct); product = newProduct; } // 先查询是否已存在相同的产品型号 ProductModel existingModel = productModelMapper.selectOne( new LambdaQueryWrapper() .eq(ProductModel::getProductId, product.getId()) .eq(ProductModel::getUnit, stockInventoryDto.getUnit()) .eq(ProductModel::getModel, stockInventoryDto.getModel()) ); Long productModelId; if (existingModel != null) { // 已存在 productModelId = existingModel.getId(); } else { // 不存在 ProductModel productModel = new ProductModel(); productModel.setProductId(product.getId()); productModel.setUnit(stockInventoryDto.getUnit()); productModel.setModel(stockInventoryDto.getModel()); productModelMapper.insert(productModel); productModelId = productModel.getId(); } stockInRecordDto.setProductId(product.getId()); stockInRecordDto.setProductModelId(productModelId); stockInventoryDto.setProductModelId(productModelId); modelId = productModelId; } stockInRecordDto.setRemark(stockInventoryDto.getRemark()); stockInRecordDto.setType("0"); // 根据产品类型设置不同的重量字段 if (stockInventoryDto.getProductType() != null && stockInventoryDto.getProductType() == 0) { stockInRecordDto.setStockInNum(stockInventoryDto.getNetWeight()); stockInRecordDto.setWeighingDate(stockInventoryDto.getWeighingDate()); stockInRecordDto.setNetWeight(stockInventoryDto.getNetWeight()); stockInRecordDto.setGrossWeight(stockInventoryDto.getGrossWeight()); stockInRecordDto.setTareWeight(stockInventoryDto.getTareWeight()); stockInRecordDto.setLicensePlateNo(stockInventoryDto.getLicensePlateNo()); stockInRecordDto.setUnit(stockInventoryDto.getUnit()); // 生成磅单 String absoluteDocPath = weighbridgeDocGenerator.generateWeighbridgeDoc(stockInRecordDto); stockInRecordDto.setWeighbridgeDocPath(absoluteDocPath); } else { stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity()); stockInRecordDto.setNetWeight(stockInventoryDto.getQualitity()); } // 保存入库记录 stockInRecordService.add(stockInRecordDto); // 2. 更新库存 StockInventory oldStockInventory = stockInventoryMapper.selectOne( new QueryWrapper().lambda() .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()) ); ProductModel productModel = productModelMapper.selectById(modelId); BigDecimal weight = compareUnit(stockInventoryDto, productModel); if (ObjectUtils.isEmpty(oldStockInventory)) { // 新增库存 StockInventory newStockInventory = new StockInventory(); newStockInventory.setProductModelId(stockInventoryDto.getProductModelId()); newStockInventory.setQualitity(weight); newStockInventory.setVersion(1); newStockInventory.setRemark(stockInventoryDto.getRemark()); newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity()); newStockInventory.setWarnNum(stockInventoryDto.getWarnNum()); newStockInventory.setProductId(stockInventoryDto.getProductId()); stockInventoryMapper.insert(newStockInventory); } else { // 更新库存 stockInventoryDto.setQualitity(weight); stockInventoryMapper.updateAddStockInventory(stockInventoryDto); } return true; } //出库调用 @Override @Transactional(rollbackFor = Exception.class) public Boolean subtractStockInventory(StockInventoryDto stockInventoryDto) { // 1. 查询产品型号和库存信息 ProductModel productModel = productModelMapper.selectById(stockInventoryDto.getProductModelId()); if (productModel == null) { throw new BaseException("产品型号不存在"); } StockInventory oldStockInventory = stockInventoryMapper.selectOne( new QueryWrapper().lambda() .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()) ); if (oldStockInventory == null) { throw new BaseException("产品库存不存在"); } // 2. 计算并转换出库数量 BigDecimal outQuantity = compareUnit(stockInventoryDto, productModel); // 3. 检查库存是否充足(考虑锁定库存) BigDecimal availableQuantity = oldStockInventory.getQualitity() .subtract(Optional.ofNullable(oldStockInventory.getLockedQuantity()).orElse(BigDecimal.ZERO)); if (outQuantity.compareTo(availableQuantity) > 0) { throw new BaseException("库存不足,当前可用库存:" + availableQuantity); } // 4. 扣减库存 stockInventoryDto.setQualitity(outQuantity); int affectedRows = stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto); if (affectedRows == 0) { throw new BaseException("扣减库存失败,可能库存不足或数据已被修改"); } // 5. 创建并保存出库记录 createAndSaveStockOutRecord(stockInventoryDto, productModel); return true; } /** * 计算并转换出库数量(统一转换为库存单位) */ private BigDecimal compareUnit(StockInventoryDto stockInventoryDto, ProductModel productModel) { // 获取原始出库数量(根据产品类型选择净重或数量) BigDecimal originalQuantity = (stockInventoryDto.getProductType() != null && stockInventoryDto.getProductType() == 0) ? stockInventoryDto.getNetWeight() : stockInventoryDto.getQualitity(); String sourceUnit = stockInventoryDto.getUnit(); String targetUnit = productModel.getUnit(); // 单位相同,直接返回 if (sourceUnit.equals(targetUnit)) { return originalQuantity; } // 单位转换 if ("吨".equals(targetUnit)) { // 转换为吨 return originalQuantity.divide(BigDecimal.valueOf(1000), 2, RoundingMode.HALF_UP); } else if ("公斤".equals(targetUnit)) { // 转换为公斤 return originalQuantity.multiply(BigDecimal.valueOf(1000)); } else { // 单位不匹配时,返回原值 return originalQuantity; } } /** * 创建并保存出库记录 */ private void createAndSaveStockOutRecord(StockInventoryDto stockInventoryDto, ProductModel productModel) { // 创建出库记录DTO StockOutRecordDto stockOutRecordDto = new StockOutRecordDto(); if (stockInventoryDto.getProductType() != null && stockInventoryDto.getProductType() == 0) { stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockOutRecordDto.setWeighingDate(stockInventoryDto.getWeighingDate()); stockOutRecordDto.setStockOutNum(stockInventoryDto.getNetWeight()); stockOutRecordDto.setNetWeight(stockInventoryDto.getNetWeight()); stockOutRecordDto.setGrossWeight(stockInventoryDto.getGrossWeight()); stockOutRecordDto.setTareWeight(stockInventoryDto.getTareWeight()); stockOutRecordDto.setWeighingOperator(stockInventoryDto.getWeighingOperator()); stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockOutRecordDto.setLicensePlateNo(stockInventoryDto.getLicensePlateNo()); stockOutRecordDto.setProductId(stockInventoryDto.getProductId()); stockOutRecordDto.setRemark(stockInventoryDto.getRemark()); stockOutRecordDto.setUnit(stockInventoryDto.getUnit()); stockOutRecordDto.setType("0"); // 生成磅单 StockInRecordDto stockInRecordDto = new StockInRecordDto(); BeanUtils.copyProperties(stockOutRecordDto, stockInRecordDto); String absoluteDocPath = weighbridgeDocGenerator.generateWeighbridgeDoc(stockInRecordDto); stockOutRecordDto.setWeighbridgeDocPath(absoluteDocPath); } else { stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity()); stockOutRecordDto.setNetWeight(stockInventoryDto.getQualitity()); stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockOutRecordDto.setProductId(stockInventoryDto.getProductId()); stockOutRecordDto.setRemark(stockInventoryDto.getRemark()); stockOutRecordDto.setUnit(stockInventoryDto.getUnit()); stockOutRecordDto.setType("0"); } stockOutRecordService.add(stockOutRecordDto); } @Override public R importStockInventory(MultipartFile file) { try { ExcelUtil util = new ExcelUtil(StockInventoryExportData.class); List list = util.importExcel(file.getInputStream()); for (StockInventoryExportData dto : list) { // 验证冻结数量 if (ObjectUtils.isNotEmpty(dto.getLockedQuantity()) && dto.getLockedQuantity().compareTo(dto.getQualitity()) > 0) { throw new RuntimeException(String.format("产品[%s %s]冻结数量不能超过库存数量", dto.getProductName(), dto.getModel())); } StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setRecordId(0L); stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_STOCK_IN.getCode()); stockInventoryDto.setQualitity(dto.getQualitity()); stockInventoryDto.setRemark(dto.getRemark()); stockInventoryDto.setNetWeight(dto.getNetWeight()); stockInventoryDto.setLockedQuantity(dto.getLockedQuantity()); stockInventoryDto.setProductName(dto.getProductName()); stockInventoryDto.setModel(dto.getModel()); stockInventoryDto.setUnit(dto.getUnit()); //通过代理对象调用 ((StockInventoryService) AopContext.currentProxy()).addstockInventory(stockInventoryDto); } return R.ok("导入成功"); } catch (Exception e) { e.printStackTrace(); 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 (stockInventory.getQualitity().compareTo(stockInventoryDto.getLockedQuantity()) < 0) { throw new RuntimeException("冻结数量不能超过库存数量"); } if (ObjectUtils.isEmpty(stockInventory.getLockedQuantity())) { stockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity()); } else { stockInventory.setLockedQuantity(stockInventory.getLockedQuantity().add(stockInventoryDto.getLockedQuantity())); } return this.updateById(stockInventory); } @Override public Boolean thawStock(StockInventoryDto stockInventoryDto) { StockInventory stockInventory = stockInventoryMapper.selectById(stockInventoryDto.getId()); if (stockInventory.getLockedQuantity().compareTo(stockInventoryDto.getLockedQuantity()) < 0) { throw new RuntimeException("解冻数量不能超过冻结数量"); } stockInventory.setLockedQuantity(stockInventory.getLockedQuantity().subtract(stockInventoryDto.getLockedQuantity())); return this.updateById(stockInventory); } }