- 在 IWmsRawMaterialService 中新增 queryStatistics 方法用于统计原材料数据 - 在 WmsRawMaterialController 中添加 /statistics 接口端点 - 在 WmsRawMaterialMapper 中新增 selectStatistics 查询方法 - 在 XML 映射文件中实现统计查询的 SQL 语句 - 在服务实现类中完成统计逻辑,按厂家、材质、规格分组计算钢卷件数和重量 - 新增 ManufacturerStatisticsVo、MaterialStatisticsVo、SpecificationStatisticsVo 和 WmsRawMaterialStatisticsVo 数据传输对象 - 实现多层级数据聚合统计功能,包括厂家、材质、规格维度的数据汇总
430 lines
18 KiB
Java
430 lines
18 KiB
Java
package com.klp.service.impl;
|
||
|
||
import cn.hutool.core.bean.BeanUtil;
|
||
import com.klp.common.core.page.TableDataInfo;
|
||
import com.klp.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.klp.common.utils.StringUtils;
|
||
import lombok.RequiredArgsConstructor;
|
||
import org.springframework.cache.annotation.CacheEvict;
|
||
import org.springframework.stereotype.Service;
|
||
import com.klp.domain.bo.WmsRawMaterialBo;
|
||
import com.klp.domain.vo.WmsRawMaterialVo;
|
||
import com.klp.domain.vo.dashboard.WmsRawMaterialStatisticsVo;
|
||
import com.klp.domain.vo.dashboard.ManufacturerStatisticsVo;
|
||
import com.klp.domain.vo.dashboard.MaterialStatisticsVo;
|
||
import com.klp.domain.vo.dashboard.SpecificationStatisticsVo;
|
||
import com.klp.domain.WmsRawMaterial;
|
||
import com.klp.mapper.WmsRawMaterialMapper;
|
||
import com.klp.service.IWmsRawMaterialService;
|
||
import com.klp.service.IWmsOrderDetailService;
|
||
import com.klp.service.IWmsOrderService;
|
||
import com.klp.service.IWmsBomService;
|
||
import com.klp.service.IWmsBomItemService;
|
||
import com.klp.domain.bo.WmsBomBo;
|
||
import com.klp.domain.bo.WmsBomItemBo;
|
||
import com.klp.domain.vo.WmsBomItemVo;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
import java.math.BigDecimal;
|
||
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
import java.util.Collection;
|
||
import java.util.Arrays;
|
||
import java.util.stream.Collectors;
|
||
import java.util.ArrayList;
|
||
|
||
/**
|
||
* 原材料Service业务层处理
|
||
*
|
||
* @author Joshi
|
||
* @date 2025-07-18
|
||
*/
|
||
@RequiredArgsConstructor
|
||
@Service
|
||
public class WmsRawMaterialServiceImpl implements IWmsRawMaterialService {
|
||
|
||
private final WmsRawMaterialMapper baseMapper;
|
||
private final IWmsOrderDetailService orderDetailService;
|
||
private final IWmsOrderService orderService;
|
||
private final IWmsBomService wmsBomService;
|
||
private final IWmsBomItemService wmsBomItemService;
|
||
|
||
/**
|
||
* 查询原材料
|
||
*/
|
||
@Override
|
||
public WmsRawMaterialVo queryById(Long rawMaterialId){
|
||
return baseMapper.selectVoById(rawMaterialId);
|
||
}
|
||
|
||
/**
|
||
* 查询原材料列表(带Redis缓存,30分钟过期)
|
||
*/
|
||
@Override
|
||
// @Cacheable(cacheNames = "wms:rawMaterial:list", key = "'bo_' + #bo + '_page_' + #pageQuery.pageNum + '_' + #pageQuery.pageSize")
|
||
public TableDataInfo<WmsRawMaterialVo> queryPageList(WmsRawMaterialBo bo, PageQuery pageQuery) {
|
||
LambdaQueryWrapper<WmsRawMaterial> lqw = buildQueryWrapper(bo);
|
||
Page<WmsRawMaterialVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||
return TableDataInfo.build(result);
|
||
}
|
||
|
||
/**
|
||
* 查询原材料列表(带BOM信息)
|
||
*/
|
||
@Override
|
||
public TableDataInfo<WmsRawMaterialVo> queryPageListWithBom(WmsRawMaterialBo bo, PageQuery pageQuery) {
|
||
LambdaQueryWrapper<WmsRawMaterial> lqw = buildQueryWrapper(bo);
|
||
Page<WmsRawMaterialVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||
|
||
// 填充BOM信息
|
||
fillBomInfo(result.getRecords());
|
||
|
||
return TableDataInfo.build(result);
|
||
}
|
||
|
||
/**
|
||
* 查询原材料列表
|
||
*/
|
||
@Override
|
||
public List<WmsRawMaterialVo> queryList(WmsRawMaterialBo bo) {
|
||
LambdaQueryWrapper<WmsRawMaterial> lqw = buildQueryWrapper(bo);
|
||
List<WmsRawMaterialVo> wmsRawMaterialVos = baseMapper.selectVoList(lqw);
|
||
// 处理空值替换为"空置"
|
||
if (wmsRawMaterialVos != null) {
|
||
for (WmsRawMaterialVo vo : wmsRawMaterialVos) {
|
||
if (vo.getSpecification() == null) {
|
||
vo.setSpecification("空置");
|
||
}
|
||
if (vo.getMaterial() == null) {
|
||
vo.setMaterial("空置");
|
||
}
|
||
if (vo.getManufacturer() == null) {
|
||
vo.setManufacturer("空置");
|
||
}
|
||
if (vo.getSurfaceTreatmentDesc() == null) {
|
||
vo.setSurfaceTreatmentDesc("空置");
|
||
}
|
||
if (vo.getZincLayer() == null) {
|
||
vo.setZincLayer("空置");
|
||
}
|
||
}
|
||
} else {
|
||
wmsRawMaterialVos = new java.util.ArrayList<>();
|
||
}
|
||
return wmsRawMaterialVos;
|
||
}
|
||
|
||
/**
|
||
* 查询原材料列表(含需求、库存、在途信息)
|
||
*/
|
||
@Override
|
||
public TableDataInfo<WmsRawMaterialVo> queryPageListWithDemand(WmsRawMaterialBo bo, PageQuery pageQuery) {
|
||
LambdaQueryWrapper<WmsRawMaterial> lqw = buildQueryWrapper(bo);
|
||
Page<WmsRawMaterialVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||
// // 填充需求、库存、在途信息
|
||
// fillDemandInfo(result.getRecords());
|
||
return TableDataInfo.build(result);
|
||
}
|
||
|
||
// /**
|
||
// * 填充原材料需求、库存、在途信息
|
||
// */
|
||
// private void fillDemandInfo(List<WmsRawMaterialVo> rawMaterialList) {
|
||
// if (rawMaterialList == null || rawMaterialList.isEmpty()) {
|
||
// return;
|
||
// }
|
||
// // 为每个原材料填充信息
|
||
// for (WmsRawMaterialVo vo : rawMaterialList) {
|
||
// Long rawMaterialId = vo.getRawMaterialId();
|
||
// // 查询库存量
|
||
// BigDecimal inventory = stockService.getStockByItemId(rawMaterialId);
|
||
// vo.setInventory(inventory != null ? inventory : BigDecimal.ZERO);
|
||
// // 查询在途量(采购计划明细)
|
||
// BigDecimal onTheWay = getOnTheWayQuantity(rawMaterialId);
|
||
// vo.setOnTheWay(onTheWay);
|
||
// // 查询需求量(订单+BOM)
|
||
// BigDecimal demand = getDemandQuantity(rawMaterialId);
|
||
// vo.setDemand(demand);
|
||
// }
|
||
// }
|
||
|
||
// /**
|
||
// * 获取在途量
|
||
// */
|
||
// private BigDecimal getOnTheWayQuantity(Long rawMaterialId) {
|
||
// WmsPurchasePlanDetailBo bo = new WmsPurchasePlanDetailBo();
|
||
// bo.setRawMaterialId(rawMaterialId);
|
||
// List<WmsPurchasePlanDetailVo> list = purchasePlanDetailService.queryList(bo);
|
||
// return list.stream()
|
||
// .filter(item -> item.getStatus() != null && item.getStatus() == 1) // 在途状态
|
||
// .map(WmsPurchasePlanDetailVo::getQuantity)
|
||
// .filter(qty -> qty != null)
|
||
// .reduce(BigDecimal.ZERO, BigDecimal::add);
|
||
// }
|
||
//
|
||
// /**
|
||
// * 获取需求量
|
||
// */
|
||
// private BigDecimal getDemandQuantity(Long rawMaterialId) {
|
||
// // 先查询包含该原材料的BOM
|
||
// WmsProductBomBo bomBo = new WmsProductBomBo();
|
||
// bomBo.setRawMaterialId(rawMaterialId);
|
||
// List<WmsProductBomVo> bomList = productBomService.queryList(bomBo);
|
||
// if (bomList.isEmpty()) {
|
||
// return BigDecimal.ZERO;
|
||
// }
|
||
// // 查询这些产品的订单明细
|
||
// BigDecimal totalDemand = BigDecimal.ZERO;
|
||
// for (WmsProductBomVo bom : bomList) {
|
||
// WmsOrderDetailBo orderDetailBo = new WmsOrderDetailBo();
|
||
// orderDetailBo.setProductId(bom.getProductId());
|
||
// List<WmsOrderDetailVo> orderDetails = orderDetailService.queryList(orderDetailBo);
|
||
// // 逐个查询订单状态,过滤出有效订单的明细
|
||
// BigDecimal productDemand = BigDecimal.ZERO;
|
||
// for (WmsOrderDetailVo detail : orderDetails) {
|
||
// // 查询订单主表状态
|
||
// WmsOrderVo order = orderService.queryById(detail.getOrderId());
|
||
// if (order != null && order.getOrderStatus() != null && order.getOrderStatus() < 2) {
|
||
// // 新建、生产中状态,累加数量
|
||
// if (detail.getQuantity() != null) {
|
||
// productDemand = productDemand.add(detail.getQuantity());
|
||
// }
|
||
// }
|
||
// }
|
||
// // 需求量 = 产品需求量 × BOM用量
|
||
// if (bom.getQuantity() != null) {
|
||
// totalDemand = totalDemand.add(productDemand.multiply(bom.getQuantity()));
|
||
// }
|
||
// }
|
||
//
|
||
// return totalDemand;
|
||
// }
|
||
|
||
private LambdaQueryWrapper<WmsRawMaterial> buildQueryWrapper(WmsRawMaterialBo bo) {
|
||
Map<String, Object> params = bo.getParams();
|
||
LambdaQueryWrapper<WmsRawMaterial> lqw = Wrappers.lambdaQuery();
|
||
lqw.eq(StringUtils.isNotBlank(bo.getRawMaterialCode()), WmsRawMaterial::getRawMaterialCode, bo.getRawMaterialCode());
|
||
|
||
// 如果同时传入了名称和规格,且值相同(搜索关键词),使用 OR 条件
|
||
boolean hasName = StringUtils.isNotBlank(bo.getRawMaterialName());
|
||
boolean hasSpec = StringUtils.isNotBlank(bo.getSpecification());
|
||
if (hasName && hasSpec && bo.getRawMaterialName().equals(bo.getSpecification())) {
|
||
// 搜索关键词:匹配名称或规格
|
||
String searchKey = bo.getRawMaterialName();
|
||
lqw.and(wrapper -> wrapper
|
||
.like(WmsRawMaterial::getRawMaterialName, searchKey)
|
||
.or()
|
||
.like(WmsRawMaterial::getSpecification, searchKey)
|
||
);
|
||
} else {
|
||
// 分别处理名称和规格
|
||
lqw.like(hasName, WmsRawMaterial::getRawMaterialName, bo.getRawMaterialName());
|
||
lqw.like(hasSpec, WmsRawMaterial::getSpecification, bo.getSpecification());
|
||
}
|
||
|
||
lqw.eq(StringUtils.isNotBlank(bo.getSteelGrade()), WmsRawMaterial::getSteelGrade, bo.getSteelGrade());
|
||
lqw.eq(StringUtils.isNotBlank(bo.getTargetColdGrade()), WmsRawMaterial::getTargetColdGrade, bo.getTargetColdGrade());
|
||
lqw.eq(bo.getBaseMaterialId() != null, WmsRawMaterial::getBaseMaterialId, bo.getBaseMaterialId());
|
||
lqw.eq(bo.getSurfaceTreatmentId() != null, WmsRawMaterial::getSurfaceTreatmentId, bo.getSurfaceTreatmentId());
|
||
lqw.eq(bo.getThickness() != null, WmsRawMaterial::getThickness, bo.getThickness());
|
||
lqw.eq(bo.getThicknessDeviation() != null, WmsRawMaterial::getThicknessDeviation, bo.getThicknessDeviation());
|
||
lqw.eq(bo.getWidth() != null, WmsRawMaterial::getWidth, bo.getWidth());
|
||
lqw.eq(bo.getTargetColdWidth() != null, WmsRawMaterial::getTargetColdWidth, bo.getTargetColdWidth());
|
||
lqw.eq(bo.getTargetColdThickness() != null, WmsRawMaterial::getTargetColdThickness, bo.getTargetColdThickness());
|
||
lqw.eq(bo.getCrown() != null, WmsRawMaterial::getCrown, bo.getCrown());
|
||
lqw.eq(bo.getCoilWeight() != null, WmsRawMaterial::getCoilWeight, bo.getCoilWeight());
|
||
lqw.eq(StringUtils.isNotBlank(bo.getSurfaceQuality()), WmsRawMaterial::getSurfaceQuality, bo.getSurfaceQuality());
|
||
lqw.eq(bo.getHardnessHv5() != null, WmsRawMaterial::getHardnessHv5, bo.getHardnessHv5());
|
||
lqw.eq(bo.getHardnessDiff() != null, WmsRawMaterial::getHardnessDiff, bo.getHardnessDiff());
|
||
lqw.eq(bo.getCompositionMn() != null, WmsRawMaterial::getCompositionMn, bo.getCompositionMn());
|
||
lqw.eq(bo.getCompositionP() != null, WmsRawMaterial::getCompositionP, bo.getCompositionP());
|
||
lqw.eq(StringUtils.isNotBlank(bo.getGrainSize()), WmsRawMaterial::getGrainSize, bo.getGrainSize());
|
||
lqw.eq(bo.getHeadTailCutFlag() != null, WmsRawMaterial::getHeadTailCutFlag, bo.getHeadTailCutFlag());
|
||
lqw.eq(StringUtils.isNotBlank(bo.getInspectionResult()), WmsRawMaterial::getInspectionResult, bo.getInspectionResult());
|
||
lqw.eq(bo.getIsEnabled() != null, WmsRawMaterial::getIsEnabled, bo.getIsEnabled());
|
||
lqw.eq(bo.getBomId() != null, WmsRawMaterial::getBomId, bo.getBomId());
|
||
lqw.eq(StringUtils.isNotBlank(bo.getMaterial()), WmsRawMaterial::getMaterial, bo.getMaterial());
|
||
lqw.eq(StringUtils.isNotBlank(bo.getSurfaceTreatmentDesc()), WmsRawMaterial::getSurfaceTreatmentDesc, bo.getSurfaceTreatmentDesc());
|
||
lqw.eq(StringUtils.isNotBlank(bo.getManufacturer()), WmsRawMaterial::getManufacturer, bo.getManufacturer());
|
||
lqw.eq(StringUtils.isNotBlank(bo.getZincLayer()), WmsRawMaterial::getZincLayer, bo.getZincLayer());
|
||
return lqw;
|
||
}
|
||
|
||
/**
|
||
* 新增原材料
|
||
*/
|
||
@Override
|
||
@Transactional(rollbackFor = Exception.class)
|
||
// @CacheEvict(cacheNames = "wms:rawMaterial:list", allEntries = true)
|
||
public WmsRawMaterialBo insertByBo(WmsRawMaterialBo bo) {
|
||
// 1. 先创建BOM头
|
||
WmsBomBo bomBo = new WmsBomBo();
|
||
bomBo.setBomCode("原材料BOM" + System.currentTimeMillis());
|
||
bomBo.setBomName("原材料BOM" + System.currentTimeMillis());
|
||
bomBo.setIsEnabled(1);
|
||
bomBo.setRemark("原材料创建时自动生成的BOM");
|
||
|
||
WmsBomBo savedBom = wmsBomService.insertByBo(bomBo);
|
||
Long bomId = savedBom.getBomId();
|
||
|
||
// 2. 创建原材料并关联BOM
|
||
WmsRawMaterial add = BeanUtil.toBean(bo, WmsRawMaterial.class);
|
||
add.setBomId(bomId);
|
||
validEntityBeforeSave(add);
|
||
boolean flag = baseMapper.insert(add) > 0;
|
||
if (flag) {
|
||
bo.setRawMaterialId(add.getRawMaterialId());
|
||
|
||
// 3. 创建默认的BOM明细项(根据截图的默认属性)
|
||
createDefaultBomItems(bomId, "原料");
|
||
}
|
||
return bo;
|
||
}
|
||
|
||
/**
|
||
* 创建默认的BOM明细项
|
||
*/
|
||
private void createDefaultBomItems(Long bomId, String type) {
|
||
List<String[]> defaultAttrs;
|
||
|
||
if ("产品".equals(type)) {
|
||
// 产品默认属性(根据截图)
|
||
defaultAttrs = Arrays.asList(
|
||
new String[]{"规格", null},
|
||
new String[]{"材质", null},
|
||
new String[]{"表面处理", null}
|
||
);
|
||
} else {
|
||
// 原料默认属性(根据截图)
|
||
defaultAttrs = Arrays.asList(
|
||
new String[]{"规格", null},
|
||
new String[]{"材质", null},
|
||
new String[]{"厂家", null}
|
||
);
|
||
}
|
||
|
||
for (String[] attr : defaultAttrs) {
|
||
WmsBomItemBo itemBo = new WmsBomItemBo();
|
||
itemBo.setBomId(bomId);
|
||
itemBo.setAttrKey(attr[0]);
|
||
itemBo.setAttrValue(attr[1]);
|
||
itemBo.setIsEnabled(1);
|
||
itemBo.setRemark("创建时自动生成的默认属性");
|
||
wmsBomItemService.insertByBo(itemBo);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 修改原材料
|
||
*/
|
||
@Override
|
||
@CacheEvict(cacheNames = "wms:rawMaterial:list", allEntries = true)
|
||
public Boolean updateByBo(WmsRawMaterialBo bo) {
|
||
WmsRawMaterial update = BeanUtil.toBean(bo, WmsRawMaterial.class);
|
||
validEntityBeforeSave(update);
|
||
return baseMapper.updateById(update) > 0;
|
||
}
|
||
|
||
/**
|
||
* 填充BOM信息
|
||
*/
|
||
private void fillBomInfo(List<WmsRawMaterialVo> rawMaterialList) {
|
||
if (rawMaterialList == null || rawMaterialList.isEmpty()) {
|
||
return;
|
||
}
|
||
|
||
for (WmsRawMaterialVo vo : rawMaterialList) {
|
||
if (vo.getBomId() != null) {
|
||
// 查询BOM明细
|
||
WmsBomItemBo bomItemBo = new WmsBomItemBo();
|
||
bomItemBo.setBomId(vo.getBomId());
|
||
List<WmsBomItemVo> bomItems = wmsBomItemService.queryList(bomItemBo);
|
||
vo.setBomItems(bomItems);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 保存前的数据校验
|
||
*/
|
||
private void validEntityBeforeSave(WmsRawMaterial entity){
|
||
//TODO 做一些数据校验,如唯一约束
|
||
}
|
||
|
||
/**
|
||
* 批量删除原材料
|
||
*/
|
||
@Override
|
||
// @CacheEvict(cacheNames = "wms:rawMaterial:list", allEntries = true)
|
||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||
if(isValid){
|
||
//TODO 做一些业务上的校验,判断是否需要校验
|
||
}
|
||
return baseMapper.deleteBatchIds(ids) > 0;
|
||
}
|
||
|
||
/**
|
||
* 统计原材料按厂家、材质、规格的钢卷件数和重量
|
||
*/
|
||
@Override
|
||
public List<ManufacturerStatisticsVo> queryStatistics() {
|
||
List<WmsRawMaterialStatisticsVo> flatList = baseMapper.selectStatistics();
|
||
|
||
Map<String, List<WmsRawMaterialStatisticsVo>> byManufacturer = flatList.stream()
|
||
.collect(Collectors.groupingBy(s -> s.getManufacturer() == null ? "空置" : s.getManufacturer()));
|
||
|
||
List<ManufacturerStatisticsVo> result = new ArrayList<>();
|
||
|
||
for (Map.Entry<String, List<WmsRawMaterialStatisticsVo>> manuEntry : byManufacturer.entrySet()) {
|
||
ManufacturerStatisticsVo manuVo = new ManufacturerStatisticsVo();
|
||
manuVo.setManufacturer(manuEntry.getKey());
|
||
|
||
List<WmsRawMaterialStatisticsVo> manuList = manuEntry.getValue();
|
||
Map<String, List<WmsRawMaterialStatisticsVo>> byMaterial = manuList.stream()
|
||
.collect(Collectors.groupingBy(s -> s.getMaterial() == null ? "空置" : s.getMaterial()));
|
||
|
||
List<MaterialStatisticsVo> materialVoList = new ArrayList<>();
|
||
int totalCoilCount = 0;
|
||
BigDecimal totalWeight = BigDecimal.ZERO;
|
||
|
||
for (Map.Entry<String, List<WmsRawMaterialStatisticsVo>> matEntry : byMaterial.entrySet()) {
|
||
MaterialStatisticsVo matVo = new MaterialStatisticsVo();
|
||
matVo.setMaterial(matEntry.getKey());
|
||
|
||
List<SpecificationStatisticsVo> specVoList = new ArrayList<>();
|
||
int matCoilCount = 0;
|
||
BigDecimal matWeight = BigDecimal.ZERO;
|
||
|
||
for (WmsRawMaterialStatisticsVo item : matEntry.getValue()) {
|
||
SpecificationStatisticsVo specVo = new SpecificationStatisticsVo();
|
||
specVo.setSpecification(item.getSpecification() == null ? "空置" : item.getSpecification());
|
||
specVo.setCoilCount(item.getCoilCount() == null ? 0 : item.getCoilCount());
|
||
specVo.setTotalWeight(item.getTotalWeight() == null ? BigDecimal.ZERO : item.getTotalWeight());
|
||
specVoList.add(specVo);
|
||
|
||
matCoilCount += item.getCoilCount() == null ? 0 : item.getCoilCount();
|
||
matWeight = matWeight.add(item.getTotalWeight() == null ? BigDecimal.ZERO : item.getTotalWeight());
|
||
}
|
||
|
||
matVo.setSpecifications(specVoList);
|
||
matVo.setTotalCoilCount(matCoilCount);
|
||
matVo.setTotalWeight(matWeight);
|
||
materialVoList.add(matVo);
|
||
|
||
totalCoilCount += matCoilCount;
|
||
totalWeight = totalWeight.add(matWeight);
|
||
}
|
||
|
||
manuVo.setMaterials(materialVoList);
|
||
manuVo.setTotalCoilCount(totalCoilCount);
|
||
manuVo.setTotalWeight(totalWeight);
|
||
result.add(manuVo);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
}
|