| | |
| | | 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.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.pojo.StockOutRecord; |
| | | import com.ruoyi.stock.pojo.StockUninventory; |
| | | import com.ruoyi.stock.service.StockOutRecordService; |
| | | import lombok.AllArgsConstructor; |
| | | 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; |
| | | |
| | | /** |
| | |
| | | * @since 2026-01-21 05:27:04 |
| | | */ |
| | | @Service |
| | | @AllArgsConstructor |
| | | public class StockOutRecordServiceImpl extends ServiceImpl<StockOutRecordMapper, StockOutRecord> 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<StockOutRecordDto> listPage(Page page, StockOutRecordDto stockOutRecordDto) { |
| | |
| | | public int update(Long id, StockOutRecordDto stockOutRecordDto) { |
| | | // 判断对象是否存在 |
| | | StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id); |
| | | if (stockOutRecord == null){ |
| | | if (stockOutRecord == null) { |
| | | throw new BaseException("该出库记录不存在,无法更新!!!"); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public int batchDelete(List<Long> ids) { |
| | | for (Long id : ids) { |
| | | // 1. 查询出库记录 |
| | | StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id); |
| | | if (stockOutRecord.getType().equals("0")) { |
| | | StockInventory stockInventory = stockInventoryMapper.selectOne(new LambdaQueryWrapper<StockInventory>().eq(StockInventory::getProductModelId, stockOutRecord.getProductModelId())); |
| | | 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<StockInventory>() |
| | | .eq(StockInventory::getProductModelId, stockOutRecord.getProductModelId()) |
| | | ); |
| | | |
| | | if (stockInventory == null) { |
| | | throw new BaseException("库存记录中没有对应的产品,无法删除!!!"); |
| | | }else { |
| | | StockInventoryDto stockInRecordDto = new StockInventoryDto(); |
| | | stockInRecordDto.setProductModelId(stockInventory.getProductModelId()); |
| | | stockInRecordDto.setQualitity(stockOutRecord.getStockOutNum()); |
| | | stockInventoryMapper.updateAddStockInventory(stockInRecordDto); |
| | | throw new BaseException("库存记录中没有对应的产品,无法删除"); |
| | | } |
| | | }else if (stockOutRecord.getType().equals("1")) { |
| | | StockUninventory stockUninventory = stockUninventoryMapper.selectOne(new LambdaQueryWrapper<StockUninventory>().eq(StockUninventory::getProductModelId, stockOutRecord.getProductModelId())); |
| | | |
| | | // 创建库存更新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<StockUninventory>() |
| | | .eq(StockUninventory::getProductModelId, stockOutRecord.getProductModelId()) |
| | | ); |
| | | |
| | | if (stockUninventory == null) { |
| | | throw new BaseException("库存记录中没有对应的产品,无法删除!!!"); |
| | | }else { |
| | | StockUninventoryDto stockUninventoryDto = new StockUninventoryDto(); |
| | | stockUninventoryDto.setProductModelId(stockUninventory.getProductModelId()); |
| | | stockUninventoryDto.setQualitity(stockOutRecord.getStockOutNum()); |
| | | stockUninventoryMapper.updateAddStockUnInventory(stockUninventoryDto); |
| | | 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); |
| | | } |
| | | |
| | |
| | | for (StockOutRecordExportData stockInRecordExportData : list) { |
| | | if (stockInRecordExportData.getType().equals("0")) { |
| | | stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockOutQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue()); |
| | | }else { |
| | | } else { |
| | | stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockInUnQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue()); |
| | | } |
| | | } |
| | | ExcelUtil<StockOutRecordExportData> util = new ExcelUtil<>(StockOutRecordExportData.class); |
| | | util.exportExcel(response,list, "出库记录信息"); |
| | | 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<StockInventory>().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("库存不足,无法扣减"); |
| | | } |
| | | } |
| | | } |
| | | } |