refactor(mat): 优化物料库存查询性能并移除冗余VO类
- 移除 MatMaterialWithInventoryVo 类,将库存相关字段直接添加到 MatMaterialVo 中 - 重构 queryPageListWithInventory 和 queryListWithInventory 方法,使用批量查询替代 N+1 查询 - 实现 batchQueryMaterialInventory 方法以提高库存信息查询效率 - 更新控制器中的返回类型从 MatMaterialWithInventoryVo 到 MatMaterialVo - 修改 Excel 导出功能以使用新的数据结构
This commit is contained in:
@@ -21,7 +21,6 @@ import com.gear.common.core.validate.QueryGroup;
|
|||||||
import com.gear.common.enums.BusinessType;
|
import com.gear.common.enums.BusinessType;
|
||||||
import com.gear.common.utils.poi.ExcelUtil;
|
import com.gear.common.utils.poi.ExcelUtil;
|
||||||
import com.gear.mat.domain.vo.MatMaterialVo;
|
import com.gear.mat.domain.vo.MatMaterialVo;
|
||||||
import com.gear.mat.domain.vo.MatMaterialWithInventoryVo;
|
|
||||||
import com.gear.mat.domain.bo.MatMaterialBo;
|
import com.gear.mat.domain.bo.MatMaterialBo;
|
||||||
import com.gear.mat.service.IMatMaterialService;
|
import com.gear.mat.service.IMatMaterialService;
|
||||||
import com.gear.common.core.page.TableDataInfo;
|
import com.gear.common.core.page.TableDataInfo;
|
||||||
@@ -44,7 +43,7 @@ public class MatMaterialController extends BaseController {
|
|||||||
* 查询配料配件基础信息列表
|
* 查询配料配件基础信息列表
|
||||||
*/
|
*/
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo<MatMaterialWithInventoryVo> list(MatMaterialBo bo, PageQuery pageQuery) {
|
public TableDataInfo<MatMaterialVo> list(MatMaterialBo bo, PageQuery pageQuery) {
|
||||||
return iMatMaterialService.queryPageListWithInventory(bo, pageQuery);
|
return iMatMaterialService.queryPageListWithInventory(bo, pageQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,8 +54,8 @@ public class MatMaterialController extends BaseController {
|
|||||||
@PostMapping("/export")
|
@PostMapping("/export")
|
||||||
public void export(MatMaterialBo bo, HttpServletResponse response) {
|
public void export(MatMaterialBo bo, HttpServletResponse response) {
|
||||||
// 使用增强的服务方法获取带库存信息的物料列表
|
// 使用增强的服务方法获取带库存信息的物料列表
|
||||||
List<MatMaterialWithInventoryVo> list = iMatMaterialService.queryListWithInventory(bo);
|
List<MatMaterialVo> list = iMatMaterialService.queryListWithInventory(bo);
|
||||||
ExcelUtil.exportExcel(list, "配料配件基础信息", MatMaterialWithInventoryVo.class, response);
|
ExcelUtil.exportExcel(list, "配料配件基础信息", MatMaterialVo.class, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -71,5 +71,19 @@ public class MatMaterialVo {
|
|||||||
@ExcelProperty(value = "备注")
|
@ExcelProperty(value = "备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在途数量(未完成入库的采购数量)
|
||||||
|
*/
|
||||||
|
private transient BigDecimal inTransitNum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划采购总数量
|
||||||
|
*/
|
||||||
|
private transient BigDecimal planNum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已入库数量
|
||||||
|
*/
|
||||||
|
private transient BigDecimal receivedNum;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.gear.mat.service;
|
|||||||
|
|
||||||
import com.gear.mat.domain.MatMaterial;
|
import com.gear.mat.domain.MatMaterial;
|
||||||
import com.gear.mat.domain.vo.MatMaterialVo;
|
import com.gear.mat.domain.vo.MatMaterialVo;
|
||||||
import com.gear.mat.domain.vo.MatMaterialWithInventoryVo;
|
|
||||||
import com.gear.mat.domain.bo.MatMaterialBo;
|
import com.gear.mat.domain.bo.MatMaterialBo;
|
||||||
import com.gear.common.core.page.TableDataInfo;
|
import com.gear.common.core.page.TableDataInfo;
|
||||||
import com.gear.common.core.domain.PageQuery;
|
import com.gear.common.core.domain.PageQuery;
|
||||||
@@ -36,7 +35,7 @@ public interface IMatMaterialService {
|
|||||||
/**
|
/**
|
||||||
* 查询配料配件基础信息列表(包含库存信息)
|
* 查询配料配件基础信息列表(包含库存信息)
|
||||||
*/
|
*/
|
||||||
List<MatMaterialWithInventoryVo> queryListWithInventory(MatMaterialBo bo);
|
List<MatMaterialVo> queryListWithInventory(MatMaterialBo bo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增配料配件基础信息
|
* 新增配料配件基础信息
|
||||||
@@ -56,5 +55,5 @@ public interface IMatMaterialService {
|
|||||||
/**
|
/**
|
||||||
* 查询配料配件基础信息列表(包含库存信息)
|
* 查询配料配件基础信息列表(包含库存信息)
|
||||||
*/
|
*/
|
||||||
TableDataInfo<MatMaterialWithInventoryVo> queryPageListWithInventory(MatMaterialBo bo, PageQuery pageQuery);
|
TableDataInfo<MatMaterialVo> queryPageListWithInventory(MatMaterialBo bo, PageQuery pageQuery);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,139 +124,156 @@ public class MatMaterialServiceImpl implements IMatMaterialService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TableDataInfo<MatMaterialWithInventoryVo> queryPageListWithInventory(MatMaterialBo bo, PageQuery pageQuery) {
|
public TableDataInfo<MatMaterialVo> queryPageListWithInventory(MatMaterialBo bo, PageQuery pageQuery) {
|
||||||
// 先查询物料基本信息
|
// 先查询物料基本信息
|
||||||
TableDataInfo<MatMaterialVo> materialTable = queryPageList(bo, pageQuery);
|
TableDataInfo<MatMaterialVo> materialTable = queryPageList(bo, pageQuery);
|
||||||
|
List<MatMaterialVo> materialList = materialTable.getRows();
|
||||||
|
|
||||||
// 将MatMaterialVo转换为MatMaterialWithInventoryVo
|
if (materialList.isEmpty()) {
|
||||||
List<MatMaterialWithInventoryVo> inventoryList = materialTable.getRows().stream()
|
return materialTable;
|
||||||
.map(material -> {
|
}
|
||||||
MatMaterialWithInventoryVo inventoryVo = new MatMaterialWithInventoryVo(material);
|
|
||||||
|
|
||||||
// 查询该物料的库存信息
|
// 批量查询所有物料的库存信息
|
||||||
List<MaterialInventoryVo> materialInventoryList = queryMaterialInventory(material.getMaterialId());
|
List<Long> materialIds = materialList.stream()
|
||||||
|
.map(MatMaterialVo::getMaterialId)
|
||||||
if (!materialInventoryList.isEmpty()) {
|
.distinct()
|
||||||
MaterialInventoryVo inventoryInfo = materialInventoryList.get(0);
|
|
||||||
inventoryVo.setInTransitNum(inventoryInfo.getInTransitNum());
|
|
||||||
inventoryVo.setPlanNum(inventoryInfo.getPlanNum());
|
|
||||||
inventoryVo.setReceivedNum(inventoryInfo.getReceivedNum());
|
|
||||||
}
|
|
||||||
|
|
||||||
return inventoryVo;
|
|
||||||
})
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
Map<Long, MaterialInventoryVo> inventoryMap = batchQueryMaterialInventory(materialIds);
|
||||||
|
|
||||||
// 构建返回结果
|
// 填充库存信息到MatMaterialVo
|
||||||
Page<MatMaterialWithInventoryVo> resultPage = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize(), materialTable.getTotal());
|
materialList.forEach(material -> {
|
||||||
resultPage.setRecords(inventoryList);
|
MaterialInventoryVo inventory = inventoryMap.get(material.getMaterialId());
|
||||||
|
if (inventory != null) {
|
||||||
|
material.setInTransitNum(inventory.getInTransitNum());
|
||||||
|
material.setPlanNum(inventory.getPlanNum());
|
||||||
|
material.setReceivedNum(inventory.getReceivedNum());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return TableDataInfo.build(resultPage);
|
return materialTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<MatMaterialWithInventoryVo> queryListWithInventory(MatMaterialBo bo) {
|
public List<MatMaterialVo> queryListWithInventory(MatMaterialBo bo) {
|
||||||
// 先查询物料基本信息
|
// 先查询物料基本信息
|
||||||
List<MatMaterialVo> materialList = queryList(bo);
|
List<MatMaterialVo> materialList = queryList(bo);
|
||||||
|
|
||||||
// 将MatMaterialVo转换为MatMaterialWithInventoryVo
|
if (materialList.isEmpty()) {
|
||||||
return materialList.stream()
|
return materialList;
|
||||||
.map(material -> {
|
}
|
||||||
MatMaterialWithInventoryVo inventoryVo = new MatMaterialWithInventoryVo(material);
|
|
||||||
|
|
||||||
// 查询该物料的库存信息
|
// 批量查询所有物料的库存信息
|
||||||
List<MaterialInventoryVo> materialInventoryList = queryMaterialInventory(material.getMaterialId());
|
List<Long> materialIds = materialList.stream()
|
||||||
|
.map(MatMaterialVo::getMaterialId)
|
||||||
if (!materialInventoryList.isEmpty()) {
|
.distinct()
|
||||||
MaterialInventoryVo inventoryInfo = materialInventoryList.get(0);
|
|
||||||
inventoryVo.setInTransitNum(inventoryInfo.getInTransitNum());
|
|
||||||
inventoryVo.setPlanNum(inventoryInfo.getPlanNum());
|
|
||||||
inventoryVo.setReceivedNum(inventoryInfo.getReceivedNum());
|
|
||||||
}
|
|
||||||
|
|
||||||
return inventoryVo;
|
|
||||||
})
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
Map<Long, MaterialInventoryVo> inventoryMap = batchQueryMaterialInventory(materialIds);
|
||||||
|
|
||||||
|
// 填充库存信息到MatMaterialVo
|
||||||
|
materialList.forEach(material -> {
|
||||||
|
MaterialInventoryVo inventory = inventoryMap.get(material.getMaterialId());
|
||||||
|
if (inventory != null) {
|
||||||
|
material.setInTransitNum(inventory.getInTransitNum());
|
||||||
|
material.setPlanNum(inventory.getPlanNum());
|
||||||
|
material.setReceivedNum(inventory.getReceivedNum());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return materialList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public List<MaterialInventoryVo> queryMaterialInventory(Long materialId) {
|
/**
|
||||||
// 创建结果列表
|
* 批量查询物料库存信息
|
||||||
List<MaterialInventoryVo> result = new ArrayList<>();
|
* 避免N+1查询问题
|
||||||
|
*/
|
||||||
// 物料ID,先做非空校验
|
private Map<Long, MaterialInventoryVo> batchQueryMaterialInventory(List<Long> materialIds) {
|
||||||
if (materialId == null) {
|
if (materialIds == null || materialIds.isEmpty()) {
|
||||||
return result;
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建采购单查询条件(materialId + 过滤删除标记)
|
Map<Long, MaterialInventoryVo> resultMap = new HashMap<>();
|
||||||
|
|
||||||
|
// 批量查询所有采购单(按materialId过滤)
|
||||||
QueryWrapper<MatPurchase> purchaseQw = new QueryWrapper<>();
|
QueryWrapper<MatPurchase> purchaseQw = new QueryWrapper<>();
|
||||||
purchaseQw.eq("material_id", materialId);
|
purchaseQw.in("material_id", materialIds);
|
||||||
purchaseQw.eq("del_flag", 0);
|
purchaseQw.eq("del_flag", 0);
|
||||||
// 直接查采购单PO
|
|
||||||
List<MatPurchase> purchaseListPo = matPurchaseMapper.selectList(purchaseQw);
|
List<MatPurchase> purchaseListPo = matPurchaseMapper.selectList(purchaseQw);
|
||||||
|
|
||||||
// 将PO转换为VO
|
// 按materialId分组
|
||||||
List<MatPurchaseVo> purchaseList = purchaseListPo.stream()
|
Map<Long, List<MatPurchase>> purchaseByMaterial = purchaseListPo.stream()
|
||||||
.map(purchase -> {
|
.collect(Collectors.groupingBy(MatPurchase::getMaterialId));
|
||||||
MatPurchaseVo vo = new MatPurchaseVo();
|
|
||||||
BeanUtils.copyProperties(purchase, vo);
|
// 查询物料基本信息
|
||||||
return vo;
|
Map<Long, MatMaterialVo> materialInfoMap = baseMapper.selectVoBatchIds(materialIds).stream()
|
||||||
})
|
.collect(Collectors.toMap(MatMaterialVo::getMaterialId, m -> m));
|
||||||
|
|
||||||
|
// 按采购单ID分组,用于批量查询入库详情
|
||||||
|
List<Long> purchaseIds = purchaseListPo.stream()
|
||||||
|
.map(MatPurchase::getPurchaseId)
|
||||||
|
.distinct()
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// 1. 查询当前物料的详细信息
|
Map<Long, List<MatPurchaseInDetailVo>> detailsByPurchaseId = Collections.emptyMap();
|
||||||
MatMaterialVo material = baseMapper.selectVoById(materialId);
|
if (!purchaseIds.isEmpty()) {
|
||||||
// 2. 初始化物料库存VO
|
MatPurchaseInDetailBo detailBo = new MatPurchaseInDetailBo();
|
||||||
MaterialInventoryVo inventory = new MaterialInventoryVo();
|
Map<String, Object> params = new HashMap<>();
|
||||||
inventory.setMaterialId(materialId);
|
params.put("purchaseIds", purchaseIds);
|
||||||
if (material != null) {
|
detailBo.setParams(params);
|
||||||
inventory.setMaterialName(material.getMaterialName());
|
List<MatPurchaseInDetailVo> allDetails = matPurchaseInDetailService.queryList(detailBo);
|
||||||
inventory.setSpec(material.getSpec());
|
detailsByPurchaseId = allDetails.stream()
|
||||||
inventory.setModel(material.getModel());
|
.collect(Collectors.groupingBy(MatPurchaseInDetailVo::getPurchaseId));
|
||||||
inventory.setUnit(material.getUnit());
|
|
||||||
inventory.setCurrentStock(material.getCurrentStock());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 计算该物料的计划总数、已入库总数、在途总数
|
// 计算每个物料的库存信息
|
||||||
BigDecimal planTotal = BigDecimal.ZERO;
|
for (Long materialId : materialIds) {
|
||||||
BigDecimal receivedTotal = BigDecimal.ZERO;
|
MaterialInventoryVo inventory = new MaterialInventoryVo();
|
||||||
BigDecimal inTransitTotal = BigDecimal.ZERO;
|
inventory.setMaterialId(materialId);
|
||||||
|
|
||||||
for (MatPurchaseVo purchase : purchaseList) {
|
// 填充物料基本信息
|
||||||
// 累加计划总数
|
MatMaterialVo material = materialInfoMap.get(materialId);
|
||||||
BigDecimal planNum = Optional.ofNullable(purchase.getPlanNum()).orElse(BigDecimal.ZERO);
|
if (material != null) {
|
||||||
planTotal = planTotal.add(planNum);
|
inventory.setMaterialName(material.getMaterialName());
|
||||||
|
inventory.setSpec(material.getSpec());
|
||||||
|
inventory.setModel(material.getModel());
|
||||||
|
inventory.setUnit(material.getUnit());
|
||||||
|
inventory.setCurrentStock(material.getCurrentStock());
|
||||||
|
}
|
||||||
|
|
||||||
// 查询该采购单下的入库详情
|
// 计算采购相关数据
|
||||||
MatPurchaseInDetailBo detailBo = new MatPurchaseInDetailBo();
|
List<MatPurchase> purchases = purchaseByMaterial.getOrDefault(materialId, Collections.emptyList());
|
||||||
detailBo.setPurchaseId(purchase.getPurchaseId());
|
BigDecimal planTotal = BigDecimal.ZERO;
|
||||||
List<MatPurchaseInDetailVo> details = matPurchaseInDetailService.queryList(detailBo);
|
BigDecimal receivedTotal = BigDecimal.ZERO;
|
||||||
|
BigDecimal inTransitTotal = BigDecimal.ZERO;
|
||||||
|
|
||||||
// 计算该采购单的已入库数量
|
for (MatPurchase purchase : purchases) {
|
||||||
BigDecimal receivedInPurchase = details.stream()
|
BigDecimal planNum = Optional.ofNullable(purchase.getPlanNum()).orElse(BigDecimal.ZERO);
|
||||||
.map(MatPurchaseInDetailVo::getInNum)
|
planTotal = planTotal.add(planNum);
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
||||||
receivedTotal = receivedTotal.add(receivedInPurchase);
|
|
||||||
|
|
||||||
// 计算该采购单的在途数量
|
// 计算该采购单的已入库数量
|
||||||
if (purchase.getStatus() != null && (purchase.getStatus() == 1 || purchase.getStatus() == 4)) {
|
List<MatPurchaseInDetailVo> details = detailsByPurchaseId.getOrDefault(purchase.getPurchaseId(), Collections.emptyList());
|
||||||
BigDecimal pending = planNum.subtract(receivedInPurchase);
|
BigDecimal receivedInPurchase = details.stream()
|
||||||
if (pending.compareTo(BigDecimal.ZERO) > 0) {
|
.map(MatPurchaseInDetailVo::getInNum)
|
||||||
inTransitTotal = inTransitTotal.add(pending);
|
.filter(Objects::nonNull)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
receivedTotal = receivedTotal.add(receivedInPurchase);
|
||||||
|
|
||||||
|
// 计算该采购单的在途数量
|
||||||
|
if (purchase.getStatus() != null && (purchase.getStatus() == 1 || purchase.getStatus() == 4)) {
|
||||||
|
BigDecimal pending = planNum.subtract(receivedInPurchase);
|
||||||
|
if (pending.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
inTransitTotal = inTransitTotal.add(pending);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inventory.setPlanNum(planTotal);
|
||||||
|
inventory.setReceivedNum(receivedTotal);
|
||||||
|
inventory.setInTransitNum(inTransitTotal);
|
||||||
|
|
||||||
|
resultMap.put(materialId, inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 设置库存VO的数值字段
|
return resultMap;
|
||||||
inventory.setPlanNum(planTotal);
|
|
||||||
inventory.setReceivedNum(receivedTotal);
|
|
||||||
inventory.setInTransitNum(inTransitTotal);
|
|
||||||
|
|
||||||
// 5. 添加到结果列表
|
|
||||||
result.add(inventory);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user