package com.ruoyi.quality.service.impl;
|
|
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.quality.dto.QualityTraceBatchOptionVo;
|
import com.ruoyi.quality.dto.QualityTraceChainVo;
|
import com.ruoyi.quality.dto.QualityTraceFinishedBatchVo;
|
import com.ruoyi.quality.dto.QualityTraceForwardExportVo;
|
import com.ruoyi.quality.dto.QualityTraceForwardVo;
|
import com.ruoyi.quality.dto.QualityTraceInputVo;
|
import com.ruoyi.quality.dto.QualityTraceInspectVo;
|
import com.ruoyi.quality.dto.QualityTraceMaterialBatchVo;
|
import com.ruoyi.quality.dto.QualityTraceOutboundVo;
|
import com.ruoyi.quality.dto.QualityTracePickVo;
|
import com.ruoyi.quality.dto.QualityTraceReportVo;
|
import com.ruoyi.quality.dto.QualityTraceReverseExportVo;
|
import com.ruoyi.quality.dto.QualityTraceReverseOrderVo;
|
import com.ruoyi.quality.dto.QualityTraceReverseVo;
|
import com.ruoyi.quality.dto.QualityTraceUnqualifiedVo;
|
import com.ruoyi.quality.mapper.QualityTraceMapper;
|
import com.ruoyi.quality.service.QualityTraceService;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
|
import java.math.BigDecimal;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Set;
|
import java.util.stream.Collectors;
|
|
@Service
|
@RequiredArgsConstructor
|
public class QualityTraceServiceImpl implements QualityTraceService {
|
|
private final QualityTraceMapper qualityTraceMapper;
|
|
@Override
|
public QualityTraceForwardVo forward(String batchNo) {
|
String no = requireBatchNo(batchNo);
|
QualityTraceForwardVo result = new QualityTraceForwardVo();
|
result.setBatchNo(no);
|
|
//1.批号命中的生产入库记录(报工入库2 / 质检合格入库6)
|
List<QualityTraceFinishedBatchVo> inbound = qualityTraceMapper.listInboundByFinishedBatch(no);
|
if (inbound.isEmpty()) {
|
result.setOutbounds(qualityTraceMapper.listOutboundByBatch(no));
|
return result;
|
}
|
Map<Long, List<QualityTraceFinishedBatchVo>> inboundByOrder = inbound.stream()
|
.filter(b -> b.getProductionOrderId() != null)
|
.collect(Collectors.groupingBy(QualityTraceFinishedBatchVo::getProductionOrderId,
|
LinkedHashMap::new, Collectors.toList()));
|
List<Long> mainIds = distinct(inbound.stream().map(QualityTraceFinishedBatchVo::getProductMainId)
|
.filter(Objects::nonNull).collect(Collectors.toList()));
|
|
//2.报工节点(含订单信息)
|
List<QualityTraceReportVo> reports = mainIds.isEmpty()
|
? new ArrayList<>() : qualityTraceMapper.listReportsByMainIds(mainIds);
|
Map<Long, List<QualityTraceReportVo>> reportsByOrder = reports.stream()
|
.filter(r -> r.getProductionOrderId() != null)
|
.collect(Collectors.groupingBy(QualityTraceReportVo::getProductionOrderId,
|
LinkedHashMap::new, Collectors.toList()));
|
Map<Long, Long> orderOfMain = new LinkedHashMap<>();
|
reports.forEach(r -> orderOfMain.putIfAbsent(r.getProductMainId(), r.getProductionOrderId()));
|
|
//3.投入物料(按报工单)
|
List<QualityTraceInputVo> inputs = mainIds.isEmpty()
|
? new ArrayList<>() : qualityTraceMapper.listInputsByMainIds(mainIds);
|
|
//4.领料批次(按订单),并用原料批号回溯供应商/采购/检验
|
List<Long> orderIds = new ArrayList<>(inboundByOrder.keySet());
|
List<QualityTracePickVo> picks = orderIds.isEmpty()
|
? new ArrayList<>() : qualityTraceMapper.listPicksByOrderIds(orderIds);
|
fillPickSource(picks);
|
Map<Long, List<QualityTracePickVo>> picksByOrder = picks.stream()
|
.filter(p -> p.getProductionOrderId() != null)
|
.collect(Collectors.groupingBy(QualityTracePickVo::getProductionOrderId,
|
LinkedHashMap::new, Collectors.toList()));
|
|
//5.检验单与不合格处理
|
List<QualityTraceInspectVo> inspects = mainIds.isEmpty()
|
? new ArrayList<>() : qualityTraceMapper.listInspectsByMainIds(mainIds);
|
List<Long> inspectIds = distinct(inspects.stream().map(QualityTraceInspectVo::getInspectId)
|
.filter(Objects::nonNull).collect(Collectors.toList()));
|
List<QualityTraceUnqualifiedVo> unqualified = inspectIds.isEmpty()
|
? new ArrayList<>() : qualityTraceMapper.listUnqualifiedByInspectIds(inspectIds);
|
Map<Long, List<QualityTraceUnqualifiedVo>> unqualifiedByInspect = unqualified.stream()
|
.filter(u -> u.getInspectId() != null)
|
.collect(Collectors.groupingBy(QualityTraceUnqualifiedVo::getInspectId));
|
inspects.forEach(ins -> ins.setUnqualifiedList(
|
unqualifiedByInspect.getOrDefault(ins.getInspectId(), new ArrayList<>())));
|
Map<Long, List<QualityTraceInspectVo>> inspectsByOrder = inspects.stream()
|
.filter(i -> i.getProductMainId() != null && orderOfMain.get(i.getProductMainId()) != null)
|
.collect(Collectors.groupingBy(i -> orderOfMain.get(i.getProductMainId()),
|
LinkedHashMap::new, Collectors.toList()));
|
|
Set<Long> chainOrderIds = new LinkedHashSet<>(inboundByOrder.keySet());
|
chainOrderIds.addAll(reportsByOrder.keySet());
|
for (Long orderId : chainOrderIds) {
|
QualityTraceChainVo chain = new QualityTraceChainVo();
|
chain.setProductionOrderId(orderId);
|
List<QualityTraceReportVo> orderReports =
|
reportsByOrder.getOrDefault(orderId, new ArrayList<>());
|
if (!orderReports.isEmpty()) {
|
QualityTraceReportVo first = orderReports.get(0);
|
chain.setNpsNo(first.getNpsNo());
|
chain.setFinishedProduct(first.getFinishedProduct());
|
chain.setUnit(first.getUnit());
|
chain.setPlanQty(first.getPlanQty());
|
chain.setCompleteQty(first.getCompleteQty());
|
chain.setOrderStatus(first.getOrderStatus());
|
chain.setOrderCreateTime(first.getOrderCreateTime());
|
}
|
chain.setBatches(inboundByOrder.getOrDefault(orderId, new ArrayList<>()));
|
chain.setReports(orderReports);
|
Set<Long> orderMainIds = orderReports.stream()
|
.map(QualityTraceReportVo::getProductMainId).filter(Objects::nonNull)
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
chain.setInputs(inputs.stream()
|
.filter(i -> i.getProductMainId() != null && orderMainIds.contains(i.getProductMainId()))
|
.collect(Collectors.toList()));
|
chain.setPicks(picksByOrder.getOrDefault(orderId, new ArrayList<>()));
|
chain.setInspects(inspectsByOrder.getOrDefault(orderId, new ArrayList<>()));
|
chain.setUnqualifiedList(chain.getInspects().stream()
|
.flatMap(i -> i.getUnqualifiedList().stream()).collect(Collectors.toList()));
|
result.getChains().add(chain);
|
}
|
result.setOutbounds(qualityTraceMapper.listOutboundByBatch(no));
|
return result;
|
}
|
|
@Override
|
public QualityTraceReverseVo reverse(String batchNo) {
|
String no = requireBatchNo(batchNo);
|
QualityTraceReverseVo result = new QualityTraceReverseVo();
|
result.setBatchNo(no);
|
|
//1.批号入库/采购/检验来源
|
List<QualityTraceMaterialBatchVo> materialInfo =
|
qualityTraceMapper.listMaterialBatchInfoByBatches(Collections.singletonList(no));
|
if (!materialInfo.isEmpty()) {
|
result.setMaterial(materialInfo.get(0));
|
}
|
|
//2.使用该批号的领料明细
|
List<QualityTracePickVo> picks = qualityTraceMapper.listPicksByBatchNo(no);
|
if (picks.isEmpty()) {
|
return result;
|
}
|
fillPickSource(picks);
|
Map<Long, List<QualityTracePickVo>> picksByOrder = picks.stream()
|
.filter(p -> p.getProductionOrderId() != null)
|
.collect(Collectors.groupingBy(QualityTracePickVo::getProductionOrderId,
|
LinkedHashMap::new, Collectors.toList()));
|
List<Long> orderIds = new ArrayList<>(picksByOrder.keySet());
|
|
//3.订单报工节点与产出成品批号
|
List<QualityTraceReportVo> reports = qualityTraceMapper.listReportsByOrderIds(orderIds);
|
Map<Long, List<QualityTraceReportVo>> reportsByOrder = reports.stream()
|
.filter(r -> r.getProductionOrderId() != null)
|
.collect(Collectors.groupingBy(QualityTraceReportVo::getProductionOrderId,
|
LinkedHashMap::new, Collectors.toList()));
|
Map<Long, List<QualityTraceFinishedBatchVo>> batchesByOrder =
|
qualityTraceMapper.listFinishedBatchesByOrderIds(orderIds).stream()
|
.filter(b -> b.getProductionOrderId() != null)
|
.collect(Collectors.groupingBy(QualityTraceFinishedBatchVo::getProductionOrderId,
|
LinkedHashMap::new, Collectors.toList()));
|
|
for (Long orderId : orderIds) {
|
QualityTraceReverseOrderVo orderVo = new QualityTraceReverseOrderVo();
|
orderVo.setProductionOrderId(orderId);
|
List<QualityTraceReportVo> orderReports =
|
reportsByOrder.getOrDefault(orderId, new ArrayList<>());
|
if (!orderReports.isEmpty()) {
|
QualityTraceReportVo first = orderReports.get(0);
|
orderVo.setNpsNo(first.getNpsNo());
|
orderVo.setFinishedProduct(first.getFinishedProduct());
|
orderVo.setUnit(first.getUnit());
|
orderVo.setPlanQty(first.getPlanQty());
|
orderVo.setCompleteQty(first.getCompleteQty());
|
orderVo.setOrderStatus(first.getOrderStatus());
|
orderVo.setOrderCreateTime(first.getOrderCreateTime());
|
}
|
List<QualityTracePickVo> orderPicks =
|
picksByOrder.getOrDefault(orderId, new ArrayList<>());
|
orderVo.setPickedQty(orderPicks.stream().map(p -> nvl(p.getQuantity()))
|
.reduce(BigDecimal.ZERO, BigDecimal::add));
|
orderVo.setPicks(orderPicks);
|
orderVo.setReports(orderReports);
|
orderVo.setFinishedBatches(batchesByOrder.getOrDefault(orderId, new ArrayList<>()));
|
result.getOrders().add(orderVo);
|
}
|
return result;
|
}
|
|
@Override
|
public List<QualityTraceForwardExportVo> forwardExportRows(String batchNo) {
|
QualityTraceForwardVo trace = forward(batchNo);
|
List<QualityTraceForwardExportVo> rows = new ArrayList<>();
|
for (QualityTraceChainVo chain : trace.getChains()) {
|
String operations = chain.getReports().stream()
|
.map(r -> StringUtils.isBlank(r.getOperationName()) ? r.getWorkOrderNo() : r.getOperationName())
|
.filter(StringUtils::isNotBlank).distinct().collect(Collectors.joining("/"));
|
String inspectResults = chain.getInspects().stream()
|
.map(i -> (StringUtils.isBlank(i.getInspectTypeName()) ? "" : i.getInspectTypeName() + ":")
|
+ (StringUtils.isBlank(i.getCheckResult()) ? "未提交" : i.getCheckResult()))
|
.collect(Collectors.joining("/"));
|
String unqualifiedResults = chain.getUnqualifiedList().stream()
|
.map(u -> (StringUtils.isBlank(u.getDealResult()) ? "待处理" : u.getDealResult())
|
+ "x" + nvl(u.getQuantity()).stripTrailingZeros().toPlainString())
|
.collect(Collectors.joining("/"));
|
if (chain.getPicks().isEmpty()) {
|
QualityTraceForwardExportVo row = newForwardRow(trace.getBatchNo(), chain, operations,
|
inspectResults, unqualifiedResults);
|
rows.add(row);
|
continue;
|
}
|
for (QualityTracePickVo pick : chain.getPicks()) {
|
QualityTraceForwardExportVo row = newForwardRow(trace.getBatchNo(), chain, operations,
|
inspectResults, unqualifiedResults);
|
row.setMaterialBatchNo(pick.getBatchNo());
|
row.setMaterialName(pick.getMaterialName());
|
row.setMaterialModel(pick.getMaterialModel());
|
row.setPickQty(pick.getQuantity());
|
row.setSupplierName(pick.getSupplierName());
|
row.setMaterialCheckResult(pick.getCheckResult());
|
rows.add(row);
|
}
|
}
|
return rows;
|
}
|
|
@Override
|
public List<QualityTraceReverseExportVo> reverseExportRows(String batchNo) {
|
QualityTraceReverseVo trace = reverse(batchNo);
|
List<QualityTraceReverseExportVo> rows = new ArrayList<>();
|
QualityTraceMaterialBatchVo material = trace.getMaterial();
|
if (trace.getOrders().isEmpty()) {
|
rows.add(newReverseRow(trace, material, null, null));
|
return rows;
|
}
|
for (QualityTraceReverseOrderVo order : trace.getOrders()) {
|
String batchNos = order.getFinishedBatches().stream()
|
.map(QualityTraceFinishedBatchVo::getBatchNo)
|
.filter(StringUtils::isNotBlank).distinct().collect(Collectors.joining("/"));
|
rows.add(newReverseRow(trace, material, order, batchNos));
|
}
|
return rows;
|
}
|
|
private QualityTraceForwardExportVo newForwardRow(String batchNo, QualityTraceChainVo chain,
|
String operations, String inspectResults,
|
String unqualifiedResults) {
|
QualityTraceForwardExportVo row = new QualityTraceForwardExportVo();
|
row.setBatchNo(batchNo);
|
row.setNpsNo(chain.getNpsNo());
|
row.setFinishedProduct(chain.getFinishedProduct());
|
row.setCompleteQty(chain.getCompleteQty());
|
row.setOperations(operations);
|
row.setInspectResults(inspectResults);
|
row.setUnqualifiedResults(unqualifiedResults);
|
return row;
|
}
|
|
private QualityTraceReverseExportVo newReverseRow(QualityTraceReverseVo trace,
|
QualityTraceMaterialBatchVo material,
|
QualityTraceReverseOrderVo order, String batchNos) {
|
QualityTraceReverseExportVo row = new QualityTraceReverseExportVo();
|
row.setBatchNo(trace.getBatchNo());
|
if (material != null) {
|
row.setMaterialName(material.getMaterialName());
|
row.setMaterialModel(material.getMaterialModel());
|
row.setUnit(material.getUnit());
|
row.setSupplierName(material.getSupplierName());
|
row.setContractNo(material.getContractNo());
|
row.setEntryDate(material.getEntryDate());
|
row.setMaterialCheckResult(material.getCheckResult());
|
}
|
if (order != null) {
|
row.setNpsNo(order.getNpsNo());
|
row.setFinishedProduct(order.getFinishedProduct());
|
row.setPickedQty(order.getPickedQty());
|
row.setFinishedBatchNos(batchNos);
|
}
|
return row;
|
}
|
|
@Override
|
public List<QualityTraceBatchOptionVo> batchOptions(String type, String keyword, Integer limit) {
|
String queryType = "material".equals(type) ? "material" : "finished";
|
int size = (limit == null || limit <= 0 || limit > 200) ? 50 : limit;
|
return qualityTraceMapper.listBatchOptions(queryType, StringUtils.isBlank(keyword) ? null : keyword.trim(), size);
|
}
|
|
/** 用原料批号回溯入库来源,补全领料行的供应商/合同/检验结论 */
|
private void fillPickSource(List<QualityTracePickVo> picks) {
|
List<String> batchNos = distinct(picks.stream().map(QualityTracePickVo::getBatchNo)
|
.filter(StringUtils::isNotBlank).collect(Collectors.toList()));
|
if (batchNos.isEmpty()) {
|
return;
|
}
|
Map<String, QualityTraceMaterialBatchVo> infoByBatch = new LinkedHashMap<>();
|
for (QualityTraceMaterialBatchVo info : qualityTraceMapper.listMaterialBatchInfoByBatches(batchNos)) {
|
if (StringUtils.isNotBlank(info.getBatchNo())) {
|
infoByBatch.putIfAbsent(info.getBatchNo(), info);
|
}
|
}
|
for (QualityTracePickVo pick : picks) {
|
QualityTraceMaterialBatchVo info = infoByBatch.get(pick.getBatchNo());
|
if (info == null) {
|
continue;
|
}
|
pick.setSupplierName(info.getSupplierName());
|
pick.setContractNo(info.getContractNo());
|
pick.setCheckResult(info.getCheckResult());
|
if (StringUtils.isBlank(pick.getMaterialName())) {
|
pick.setMaterialName(info.getMaterialName());
|
}
|
if (StringUtils.isBlank(pick.getMaterialModel())) {
|
pick.setMaterialModel(info.getMaterialModel());
|
}
|
if (StringUtils.isBlank(pick.getUnit())) {
|
pick.setUnit(info.getUnit());
|
}
|
}
|
}
|
|
private String requireBatchNo(String batchNo) {
|
if (StringUtils.isBlank(batchNo)) {
|
throw new ServiceException("批号不能为空");
|
}
|
return batchNo.trim();
|
}
|
|
private <T> List<T> distinct(List<T> ids) {
|
return ids.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
}
|
|
private BigDecimal nvl(BigDecimal value) {
|
return value == null ? BigDecimal.ZERO : value;
|
}
|
}
|