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.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.enums.StockInUnQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.EnumUtil; import com.ruoyi.common.utils.OrderUtils; import com.ruoyi.common.utils.bean.BeanUtils; 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.StockOutRecordExportData; import com.ruoyi.stock.mapper.StockInventoryMapper; import com.ruoyi.stock.mapper.StockOutRecordMapper; import com.ruoyi.stock.mapper.StockUninventoryMapper; import com.ruoyi.stock.pojo.StockInventory; import com.ruoyi.stock.pojo.StockOutRecord; import com.ruoyi.stock.pojo.StockUninventory; import com.ruoyi.stock.service.StockOutRecordService; import com.ruoyi.stock.word.WeighbridgeDocGenerator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; /** *

* 出库记录表 服务实现类 *

* * @author 芯导软件(江苏)有限公司 * @since 2026-01-21 05:27:04 */ @Service public class StockOutRecordServiceImpl extends ServiceImpl implements StockOutRecordService { @Autowired private StockOutRecordMapper stockOutRecordMapper; @Autowired private StockInventoryMapper stockInventoryMapper; @Autowired private StockUninventoryMapper stockUninventoryMapper; @Autowired private WeighbridgeDocGenerator weighbridgeDocGenerator; @Autowired private ProductModelMapper productModelMapper; @Override public IPage listPage(Page page, StockOutRecordDto stockOutRecordDto) { return stockOutRecordMapper.listPage(page, stockOutRecordDto); } @Override public int add(StockOutRecordDto stockOutRecordDto) { String no = OrderUtils.countTodayByCreateTime(stockOutRecordMapper, "CK"); stockOutRecordDto.setOutboundBatches(no); return stockOutRecordMapper.insert(stockOutRecordDto); } @Override public int update(Long id, StockOutRecordDto stockOutRecordDto) { // 判断对象是否存在 StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id); if (stockOutRecord == null) { throw new BaseException("该出库记录不存在,无法更新!!!"); } String[] ignoreProperties = {"id", "outbound_batches"};//排除id属性 BeanUtils.copyProperties(stockOutRecordDto, stockOutRecord, ignoreProperties); return stockOutRecordMapper.updateById(stockOutRecord); } @Override @Transactional(rollbackFor = Exception.class) public int batchDelete(List ids) { for (Long id : ids) { // 1. 查询出库记录 StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id); if (stockOutRecord == null) { throw new BaseException("出库记录不存在,ID:" + id); } // 2. 查询产品型号(用于单位转换) ProductModel productModel = productModelMapper.selectById(stockOutRecord.getProductModelId()); if (productModel == null) { throw new BaseException("产品型号不存在,无法删除"); } // 3. 获取出库数量并进行单位转换 BigDecimal stockOutNum = stockOutRecord.getStockOutNum(); String sourceUnit = stockOutRecord.getUnit(); // 出库记录中保存的单位 String targetUnit = productModel.getUnit(); // 转换出库数量为库存单位(删除时需要加回库存,所以需要转换) BigDecimal convertedQuantity = convertQuantityToStockUnit(stockOutNum, sourceUnit, targetUnit); // 4. 根据出库类型处理不同的库存表 if ("0".equals(stockOutRecord.getType())) { // 正常出库,恢复库存 StockInventory stockInventory = stockInventoryMapper.selectOne( new LambdaQueryWrapper() .eq(StockInventory::getProductModelId, stockOutRecord.getProductModelId()) ); if (stockInventory == null) { throw new BaseException("库存记录中没有对应的产品,无法删除"); } // 创建库存更新DTO StockInventoryDto inventoryDto = new StockInventoryDto(); inventoryDto.setProductModelId(stockInventory.getProductModelId()); inventoryDto.setQualitity(convertedQuantity); // 加回库存 int affectedRows = stockInventoryMapper.updateAddStockInventory(inventoryDto); if (affectedRows == 0) { throw new BaseException("恢复库存失败"); } } else if ("1".equals(stockOutRecord.getType())) { // 非正常出库,恢复非正常库存 StockUninventory stockUninventory = stockUninventoryMapper.selectOne( new LambdaQueryWrapper() .eq(StockUninventory::getProductModelId, stockOutRecord.getProductModelId()) ); if (stockUninventory == null) { throw new BaseException("非正常库存记录中没有对应的产品,无法删除"); } // 创建非正常库存更新DTO StockUninventoryDto uninventoryDto = new StockUninventoryDto(); uninventoryDto.setProductModelId(stockUninventory.getProductModelId()); uninventoryDto.setQualitity(convertedQuantity); // 加回非正常库存 int affectedRows = stockUninventoryMapper.updateAddStockUnInventory(uninventoryDto); if (affectedRows == 0) { throw new BaseException("恢复非正常库存失败"); } } } // 5. 批量删除出库记录 return stockOutRecordMapper.deleteBatchIds(ids); } @Override public void exportStockOutRecord(HttpServletResponse response, StockOutRecordDto stockOutRecordDto) { List list = stockOutRecordMapper.listStockOutRecordExportData(stockOutRecordDto); for (StockOutRecordExportData stockInRecordExportData : list) { if (stockInRecordExportData.getType().equals("0")) { stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockOutQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue()); } else { stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockInUnQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue()); } } ExcelUtil util = new ExcelUtil<>(StockOutRecordExportData.class); util.exportExcel(response, list, "出库记录信息"); } @Override public int editStockOut(StockOutRecordDto stockOutRecordDto) { if (stockOutRecordDto.getId() == null) { throw new BaseException("出库记录ID不能为空"); } // 1. 查询原始出库记录 StockOutRecord originalRecord = stockOutRecordMapper.selectById(stockOutRecordDto.getId()); if (originalRecord == null) { throw new BaseException("出库记录不存在"); } // 2. 查询产品型号信息(用于单位转换) ProductModel productModel = productModelMapper.selectById(originalRecord.getProductModelId()); if (productModel == null) { throw new BaseException("产品型号不存在"); } // 3. 获取原始出库数量及其单位 BigDecimal originalOutNum = originalRecord.getStockOutNum(); // 原始记录中存储的数量(可能是吨或公斤) String originalUnit = originalRecord.getUnit(); // 原始记录的单位(吨、公斤等) String stockUnit = productModel.getUnit(); // 库存单位 // 将原始出库数量转换为库存单位 BigDecimal originalOutNumInStockUnit = convertQuantityToStockUnit(originalOutNum, originalUnit, stockUnit); // 4. 获取新出库数量及其单位 BigDecimal newOutNum = stockOutRecordDto.getNetWeight(); // 新输入的数量 if (newOutNum == null) { throw new BaseException("出库数量不能为空"); } String newUnit = stockOutRecordDto.getUnit(); // 新输入的单位 // 将新出库数量转换为库存单位 BigDecimal newOutNumInStockUnit = convertQuantityToStockUnit(newOutNum, newUnit, stockUnit); // 5. 计算库存变化量(使用统一转换后的库存单位值) // 出库数量变化量(正数表示出库变多,需要多扣库存;负数表示出库变少,需要加回库存) BigDecimal diffQuantity = newOutNumInStockUnit.subtract(originalOutNumInStockUnit); // 转换为库存变化量:出库变多(diffQuantity > 0)时,库存减少;出库变少(diffQuantity < 0)时,库存增加 BigDecimal inventoryChange = diffQuantity.negate(); // 6. 更新出库记录(保存用户输入的原始数值和单位) stockOutRecordDto.setStockOutNum(stockOutRecordDto.getNetWeight()); // 保存用户输入的值 stockOutRecordDto.setUnit(stockOutRecordDto.getUnit()); // 保存用户输入的单位 // 7. 生成磅单 StockInRecordDto stockInRecordDto = new StockInRecordDto(); BeanUtils.copyProperties(stockOutRecordDto, stockInRecordDto); stockInRecordDto.setStockInNum(stockOutRecordDto.getStockOutNum()); String absoluteDocPath = weighbridgeDocGenerator.generateWeighbridgeDoc(stockInRecordDto); stockOutRecordDto.setWeighbridgeDocPath(absoluteDocPath); int updateResult = stockOutRecordMapper.updateById(stockOutRecordDto); // 8. 更新库存(仅在数量发生变化时) if (inventoryChange.compareTo(BigDecimal.ZERO) != 0) { updateInventoryForStockOut(stockOutRecordDto.getProductId(), inventoryChange); } return updateResult; } /** * 将数量转换为库存单位 * * @param quantity 原始数量 * @param sourceUnit 原始单位 * @param targetUnit 目标单位(库存单位) * @return 转换后的数量 */ private BigDecimal convertQuantityToStockUnit(BigDecimal quantity, String sourceUnit, String targetUnit) { if (quantity == null) { throw new BaseException("数量不能为空"); } // 如果源单位为空,直接返回原值 if (sourceUnit == null || sourceUnit.isEmpty()) { return quantity; } // 如果源单位和目标单位相同,直接返回 if (sourceUnit.equals(targetUnit)) { return quantity; } // 单位转换 if ("吨".equals(targetUnit)) { // 目标单位是吨,需要将源单位转换为吨 if ("公斤".equals(sourceUnit)) { // 公斤转吨:除以1000 return quantity.divide(BigDecimal.valueOf(1000), 2, RoundingMode.HALF_UP); } else if ("克".equals(sourceUnit)) { // 克转吨:除以1000000 return quantity.divide(BigDecimal.valueOf(1000000), 2, RoundingMode.HALF_UP); } } else if ("公斤".equals(targetUnit)) { // 目标单位是公斤 if ("吨".equals(sourceUnit)) { // 吨转公斤:乘以1000 return quantity.multiply(BigDecimal.valueOf(1000)); } else if ("克".equals(sourceUnit)) { // 克转公斤:除以1000 return quantity.divide(BigDecimal.valueOf(1000), 2, RoundingMode.HALF_UP); } } else if ("克".equals(targetUnit)) { // 目标单位是克 if ("吨".equals(sourceUnit)) { // 吨转克:乘以1000000 return quantity.multiply(BigDecimal.valueOf(1000000)); } else if ("公斤".equals(sourceUnit)) { // 公斤转克:乘以1000 return quantity.multiply(BigDecimal.valueOf(1000)); } } // 无法转换时返回原值 return quantity; } /** * 更新库存(出库场景) * * @param productId 产品ID * @param inventoryChange 库存变化量(正数为增加库存,负数为减少库存) */ private void updateInventoryForStockOut(Long productId, BigDecimal inventoryChange) { // 查询当前库存 StockInventory stockInventory = stockInventoryMapper.selectOne( new QueryWrapper().lambda() .eq(StockInventory::getProductId, productId) ); if (stockInventory == null) { throw new BaseException("库存记录不存在"); } // 创建库存更新DTO StockInventoryDto inventoryDto = new StockInventoryDto(); BeanUtils.copyProperties(stockInventory, inventoryDto); inventoryDto.setQualitity(inventoryChange.abs()); // 根据库存变化量调用不同的更新方法 if (inventoryChange.compareTo(BigDecimal.ZERO) > 0) { // 库存增加(出库数量变少,需要加回库存) int affectedRows = stockInventoryMapper.updateAddStockInventory(inventoryDto); if (affectedRows == 0) { throw new BaseException("更新库存失败"); } } else { // 库存减少(出库数量变多,需要多扣库存) int affectedRows = stockInventoryMapper.updateSubtractStockInventory(inventoryDto); if (affectedRows == 0) { throw new BaseException("库存不足,无法扣减"); } } } }