feat(mat-purchase): 采购对应配料的在库和在途

- 在 IMatPurchaseService 中添加 queryMaterialInventory 和 queryPurchasePlanMaterialInventory 方法
- 在 MatPurchaseController 中新增库存查询接口,包括按物料ID查询、查询所有物料库存、查询采购计划库存
- 在 MatPurchaseServiceImpl 中实现库存信息查询逻辑,计算当前库存、在途数量、已入库数量等
- 新增 MaterialInventoryVo 和 PurchasePlanMaterialInventoryVo 视图对象用于库存信息展示
- 集成 matMaterialService 和 matPurchaseInDetailService 来获取完整的库存数据
This commit is contained in:
2026-01-30 16:52:45 +08:00
parent 83e8ad2a9c
commit 0c0f4d7f97
5 changed files with 346 additions and 1 deletions

View File

@@ -21,6 +21,8 @@ import com.gear.common.core.validate.QueryGroup;
import com.gear.common.enums.BusinessType;
import com.gear.common.utils.poi.ExcelUtil;
import com.gear.mat.domain.vo.MatPurchaseVo;
import com.gear.mat.domain.vo.MaterialInventoryVo;
import com.gear.mat.domain.vo.PurchasePlanMaterialInventoryVo;
import com.gear.mat.domain.bo.MatPurchaseBo;
import com.gear.mat.service.IMatPurchaseService;
import com.gear.common.core.page.TableDataInfo;
@@ -99,4 +101,35 @@ public class MatPurchaseController extends BaseController {
@PathVariable Long[] purchaseIds) {
return toAjax(iMatPurchaseService.deleteWithValidByIds(Arrays.asList(purchaseIds), true));
}
/**
* 获取物料库存信息(当前库存和在途数量)
*
* @param materialId 物料ID
*/
@GetMapping("/inventory/{materialId}")
public R<List<MaterialInventoryVo>> getMaterialInventory(@PathVariable Long materialId) {
List<MaterialInventoryVo> inventoryList = iMatPurchaseService.queryMaterialInventory(materialId);
return R.ok(inventoryList);
}
/**
* 获取所有物料库存信息(当前库存和在途数量)
*/
@GetMapping("/inventory")
public R<List<MaterialInventoryVo>> getAllMaterialInventory() {
List<MaterialInventoryVo> inventoryList = iMatPurchaseService.queryMaterialInventory(null);
return R.ok(inventoryList);
}
/**
* 获取采购计划中所有物料的库存信息(当前库存和在途数量)
*
* @param purchaseId 采购单ID
*/
@GetMapping("/plan-inventory/{purchaseId}")
public R<List<PurchasePlanMaterialInventoryVo>> getPurchasePlanMaterialInventory(@PathVariable Long purchaseId) {
List<PurchasePlanMaterialInventoryVo> inventoryList = iMatPurchaseService.queryPurchasePlanMaterialInventory(purchaseId);
return R.ok(inventoryList);
}
}

View File

@@ -0,0 +1,66 @@
package com.gear.mat.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* 物料库存信息视图对象
*
* @author ruoyi
* @date 2026-01-30
*/
@Data
public class MaterialInventoryVo {
/**
* 物料ID
*/
private Long materialId;
/**
* 物料名称
*/
private String materialName;
/**
* 规格
*/
private String spec;
/**
* 型号
*/
private String model;
/**
* 单位
*/
private String unit;
/**
* 当前库存数量
*/
private BigDecimal currentStock;
/**
* 在途数量(未完成入库的采购数量)
*/
private BigDecimal inTransitNum;
/**
* 计划采购总数量
*/
private BigDecimal planNum;
/**
* 已入库数量
*/
private BigDecimal receivedNum;
public MaterialInventoryVo() {
this.currentStock = BigDecimal.ZERO;
this.inTransitNum = BigDecimal.ZERO;
this.planNum = BigDecimal.ZERO;
this.receivedNum = BigDecimal.ZERO;
}
}

View File

@@ -0,0 +1,76 @@
package com.gear.mat.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* 采购计划物料库存信息视图对象
*
* @author ruoyi
* @date 2026-01-30
*/
@Data
public class PurchasePlanMaterialInventoryVo {
/**
* 采购单ID
*/
private Long purchaseId;
/**
* 采购单号
*/
private String purchaseNo;
/**
* 物料ID
*/
private Long materialId;
/**
* 物料名称
*/
private String materialName;
/**
* 规格
*/
private String spec;
/**
* 型号
*/
private String model;
/**
* 单位
*/
private String unit;
/**
* 计划采购数量
*/
private BigDecimal planNum;
/**
* 当前库存数量
*/
private BigDecimal currentStock;
/**
* 在途数量(未完成入库的采购数量)
*/
private BigDecimal inTransitNum;
/**
* 已入库数量
*/
private BigDecimal receivedNum;
public PurchasePlanMaterialInventoryVo() {
this.planNum = BigDecimal.ZERO;
this.currentStock = BigDecimal.ZERO;
this.inTransitNum = BigDecimal.ZERO;
this.receivedNum = BigDecimal.ZERO;
}
}

View File

@@ -2,9 +2,11 @@ package com.gear.mat.service;
import com.gear.mat.domain.MatPurchase;
import com.gear.mat.domain.vo.MatPurchaseVo;
import com.gear.mat.domain.vo.MaterialInventoryVo;
import com.gear.mat.domain.bo.MatPurchaseBo;
import com.gear.common.core.page.TableDataInfo;
import com.gear.common.core.domain.PageQuery;
import com.gear.mat.domain.vo.PurchasePlanMaterialInventoryVo;
import java.util.Collection;
import java.util.List;
@@ -46,4 +48,14 @@ public interface IMatPurchaseService {
* 校验并批量删除采购单主(管理在途库存)信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 查询物料库存信息(当前库存和在途数量)
*/
List<MaterialInventoryVo> queryMaterialInventory(Long materialId);
/**
* 查询采购计划中所有物料的库存信息(当前库存和在途数量)
*/
List<PurchasePlanMaterialInventoryVo> queryPurchasePlanMaterialInventory(Long purchaseId);
}

View File

@@ -8,17 +8,23 @@ import com.gear.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.gear.mat.domain.vo.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.gear.mat.domain.bo.MatPurchaseBo;
import com.gear.mat.domain.vo.MatPurchaseVo;
import com.gear.mat.domain.MatPurchase;
import com.gear.mat.mapper.MatPurchaseMapper;
import com.gear.mat.service.IMatPurchaseService;
import com.gear.mat.service.IMatMaterialService;
import com.gear.mat.service.IMatPurchaseInDetailService;
import com.gear.mat.domain.bo.MatPurchaseInDetailBo;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.ArrayList;
import java.math.BigDecimal;
import java.util.stream.Collectors;
/**
* 采购单主管理在途库存Service业务层处理
@@ -31,6 +37,8 @@ import java.util.Collection;
public class MatPurchaseServiceImpl implements IMatPurchaseService {
private final MatPurchaseMapper baseMapper;
private final IMatMaterialService matMaterialService;
private final IMatPurchaseInDetailService matPurchaseInDetailService;
/**
* 查询采购单主(管理在途库存)
@@ -134,4 +142,154 @@ public class MatPurchaseServiceImpl implements IMatPurchaseService {
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public List<MaterialInventoryVo> queryMaterialInventory(Long materialId) {
// 创建结果列表
List<MaterialInventoryVo> result = new ArrayList<>();
// 构建查询条件
MatPurchaseBo purchaseBo = new MatPurchaseBo();
if (materialId != null) {
purchaseBo.setMaterialId(materialId);
}
// 查询所有相关的采购单
List<MatPurchaseVo> purchaseList = queryList(purchaseBo);
// 按物料ID分组
Map<Long, List<MatPurchaseVo>> purchaseMap = purchaseList.stream()
.collect(Collectors.groupingBy(MatPurchaseVo::getMaterialId));
for (Long matId : purchaseMap.keySet()) {
// 获取物料信息
MatMaterialVo material = matMaterialService.queryById(matId);
MaterialInventoryVo inventory = new MaterialInventoryVo();
inventory.setMaterialId(matId);
if (material != null) {
inventory.setMaterialName(material.getMaterialName());
inventory.setSpec(material.getSpec());
inventory.setModel(material.getModel());
inventory.setUnit(material.getUnit());
inventory.setCurrentStock(material.getCurrentStock());
}
List<MatPurchaseVo> purchases = purchaseMap.get(matId);
// 计算计划总数
BigDecimal planTotal = purchases.stream()
.map(MatPurchaseVo::getPlanNum)
.filter(num -> num != null)
.reduce(BigDecimal.ZERO, BigDecimal::add);
inventory.setPlanNum(planTotal);
// 计算已入库数量和在途数量
BigDecimal receivedTotal = BigDecimal.ZERO;
BigDecimal inTransitTotal = BigDecimal.ZERO;
for (MatPurchaseVo purchase : purchases) {
// 查询该采购单下的入库详情
MatPurchaseInDetailBo detailBo = new MatPurchaseInDetailBo();
detailBo.setPurchaseId(purchase.getPurchaseId());
List<MatPurchaseInDetailVo> details = matPurchaseInDetailService.queryList(detailBo);
// 计算该采购单的已入库数量
BigDecimal receivedInPurchase = details.stream()
.map(MatPurchaseInDetailVo::getInNum)
.filter(num -> num != null)
.reduce(BigDecimal.ZERO, BigDecimal::add);
receivedTotal = receivedTotal.add(receivedInPurchase);
// 根据采购单状态判断在途数量
// 1-待入(在途) 2-已完成(全部入库) 3-已取消(归零) 4-部分入库
if (purchase.getStatus() != null && (purchase.getStatus() == 1 || purchase.getStatus() == 4)) {
// 在途或部分入库,计算未入库数量
BigDecimal pending = purchase.getPlanNum().subtract(receivedInPurchase);
if (pending.compareTo(BigDecimal.ZERO) > 0) {
inTransitTotal = inTransitTotal.add(pending);
}
}
}
inventory.setReceivedNum(receivedTotal);
inventory.setInTransitNum(inTransitTotal);
result.add(inventory);
}
return result;
}
@Override
public List<PurchasePlanMaterialInventoryVo> queryPurchasePlanMaterialInventory(Long purchaseId) {
List<PurchasePlanMaterialInventoryVo> result = new ArrayList<>();
if (purchaseId == null) {
return result;
}
// 查询采购单信息
MatPurchaseVo purchase = queryById(purchaseId);
if (purchase == null) {
return result;
}
// 获取物料信息
MatMaterialVo material = matMaterialService.queryById(purchase.getMaterialId());
// 创建库存信息对象
PurchasePlanMaterialInventoryVo inventory = new PurchasePlanMaterialInventoryVo();
inventory.setPurchaseId(purchase.getPurchaseId());
inventory.setPurchaseNo(purchase.getPurchaseNo());
inventory.setMaterialId(purchase.getMaterialId());
if (material != null) {
inventory.setMaterialName(material.getMaterialName());
inventory.setSpec(material.getSpec());
inventory.setModel(material.getModel());
inventory.setUnit(material.getUnit());
inventory.setCurrentStock(material.getCurrentStock());
}
// 设置计划采购数量
inventory.setPlanNum(purchase.getPlanNum());
// 查询该采购单下的入库详情
MatPurchaseInDetailBo detailBo = new MatPurchaseInDetailBo();
detailBo.setPurchaseId(purchase.getPurchaseId());
List<MatPurchaseInDetailVo> details = matPurchaseInDetailService.queryList(detailBo);
// 计算已入库数量
BigDecimal receivedTotal = details.stream()
.map(MatPurchaseInDetailVo::getInNum)
.filter(num -> num != null)
.reduce(BigDecimal.ZERO, BigDecimal::add);
inventory.setReceivedNum(receivedTotal);
// 根据采购单状态判断在途数量
// 1-待入(在途) 2-已完成(全部入库) 3-已取消(归零) 4-部分入库
if (purchase.getStatus() != null && (purchase.getStatus() == 1 || purchase.getStatus() == 4)) {
// 在途或部分入库,计算未入库数量
BigDecimal pending = purchase.getPlanNum().subtract(receivedTotal);
if (pending.compareTo(BigDecimal.ZERO) > 0) {
inventory.setInTransitNum(pending);
} else {
inventory.setInTransitNum(BigDecimal.ZERO);
}
} else {
// 已完成或已取消,没有在途数量
inventory.setInTransitNum(BigDecimal.ZERO);
}
result.add(inventory);
return result;
}
}