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;
|
|
/**
|
* <p>
|
* 出库记录表 服务实现类
|
* </p>
|
*
|
* @author 芯导软件(江苏)有限公司
|
* @since 2026-01-21 05:27:04
|
*/
|
@Service
|
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) {
|
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<Long> 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<StockInventory>()
|
.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<StockUninventory>()
|
.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<StockOutRecordExportData> 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<StockOutRecordExportData> 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<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("库存不足,无法扣减");
|
}
|
}
|
}
|
}
|