From 49e79814c7680f259b3be26d8fe7f5486a8cc33d Mon Sep 17 00:00:00 2001
From: gongchunyi <deslre0381@gmail.com>
Date: 星期日, 02 八月 2026 23:02:21 +0800
Subject: [PATCH] 暂存
---
src/test/java/com/ruoyi/production/ProcessRouteItemCopyTest.java | 352 +++++++++++++++++++++++++
src/test/java/com/ruoyi/production/BomStructureCopyTest.java | 487 ++++++++++++++++++++++++++++++++++
2 files changed, 839 insertions(+), 0 deletions(-)
diff --git a/src/test/java/com/ruoyi/production/BomStructureCopyTest.java b/src/test/java/com/ruoyi/production/BomStructureCopyTest.java
new file mode 100644
index 0000000..332b9e0
--- /dev/null
+++ b/src/test/java/com/ruoyi/production/BomStructureCopyTest.java
@@ -0,0 +1,487 @@
+package com.ruoyi.production;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.basic.mapper.ProductModelMapper;
+import com.ruoyi.basic.pojo.ProductModel;
+import com.ruoyi.production.mapper.ProductBomMapper;
+import com.ruoyi.production.mapper.ProductStructureMapper;
+import com.ruoyi.production.pojo.ProductBom;
+import com.ruoyi.production.pojo.ProductStructure;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.Rollback;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * BOM缁撴瀯琛ラ綈娴嬭瘯銆�
+ */
+@SpringBootTest
+public class BomStructureCopyTest {
+
+ @Autowired
+ private ProductModelMapper productModelMapper;
+
+ @Autowired
+ private ProductBomMapper productBomMapper;
+
+ @Autowired
+ private ProductStructureMapper productStructureMapper;
+
+ @Test
+ @Rollback(false)
+ @Transactional(rollbackFor = Exception.class)
+ public void copyAllProductBomStructureByProductId() {
+ List<ProductModel> allProductModels = productModelMapper.selectList(
+ Wrappers.<ProductModel>lambdaQuery()
+ .isNotNull(ProductModel::getProductId)
+ .orderByAsc(ProductModel::getProductId)
+ .orderByAsc(ProductModel::getId)
+ );
+ if (CollectionUtils.isEmpty(allProductModels)) {
+ throw new IllegalStateException("鏈煡璇㈠埌浠讳綍浜у搧瑙勬牸");
+ }
+
+ Map<Long, List<ProductModel>> productModelGroups = allProductModels.stream()
+ .collect(Collectors.groupingBy(ProductModel::getProductId, LinkedHashMap::new, Collectors.toList()));
+
+ List<CopySummary> summaries = new ArrayList<>();
+ for (Map.Entry<Long, List<ProductModel>> entry : productModelGroups.entrySet()) {
+ CopySummary summary = copyBomStructure(entry.getKey(), entry.getValue());
+ summaries.add(summary);
+ printProductSummary(summary);
+ }
+
+ printBatchSummary(summaries);
+ }
+
+ private CopySummary copyBomStructure(Long productId, List<ProductModel> productModels) {
+ if (CollectionUtils.isEmpty(productModels)) {
+ return CopySummary.skipped(productId, 0, 0, "鏈煡璇㈠埌浜у搧澶х被瀵瑰簲鐨勮鏍�");
+ }
+
+ Map<Long, ProductModel> productModelMap = productModels.stream()
+ .collect(Collectors.toMap(ProductModel::getId, item -> item, (left, right) -> left, LinkedHashMap::new));
+ List<Long> productModelIds = new ArrayList<>(productModelMap.keySet());
+
+ List<ProductBom> bomList = productBomMapper.selectList(
+ Wrappers.<ProductBom>lambdaQuery()
+ .in(ProductBom::getProductModelId, productModelIds)
+ .orderByAsc(ProductBom::getId)
+ );
+ if (CollectionUtils.isEmpty(bomList)) {
+ return CopySummary.skipped(productId, productModels.size(), 0, "鏈煡璇㈠埌浜у搧澶х被瀵瑰簲鐨凚OM");
+ }
+
+ Map<Integer, List<ProductStructure>> structureMap = loadStructureMap(bomList);
+ ProductBom templateBom = findTemplateBomOrNull(bomList, structureMap);
+ if (templateBom == null) {
+ return CopySummary.skipped(productId, productModels.size(), bomList.size(), "褰撳墠浜у搧澶х被涓嬫病鏈夊彲浣滀负妯℃澘鐨勫畬鏁碆OM缁撴瀯");
+ }
+
+ List<ProductStructure> templateStructures = structureMap.get(templateBom.getId());
+ ProductStructure templateRoot = requireSingleRoot(templateBom, templateStructures);
+ List<ProductStructure> templateChildren = templateStructures.stream()
+ .filter(item -> !isRoot(item))
+ .sorted(Comparator.comparing(ProductStructure::getId))
+ .collect(Collectors.toList());
+ if (templateChildren.isEmpty()) {
+ throw new IllegalStateException("妯℃澘BOM娌℃湁鍙鍒剁殑瀛愮粨鏋勶紝bomId=" + templateBom.getId());
+ }
+
+ int copiedBomCount = 0;
+ int skippedBomCount = 0;
+ int insertedStructureCount = 0;
+
+ for (ProductBom targetBom : bomList) {
+ if (Objects.equals(templateBom.getId(), targetBom.getId())) {
+ skippedBomCount++;
+ continue;
+ }
+
+ List<ProductStructure> targetStructures = structureMap.getOrDefault(targetBom.getId(), Collections.emptyList());
+ if (hasChildNodes(targetStructures)) {
+ skippedBomCount++;
+ continue;
+ }
+
+ ProductModel targetModel = productModelMap.get(targetBom.getProductModelId());
+ if (targetModel == null) {
+ throw new IllegalStateException("BOM鍏宠仈鐨勮鏍间笉灞炰簬褰撳墠浜у搧澶х被锛宐omId=" + targetBom.getId()
+ + "锛宲roductModelId=" + targetBom.getProductModelId());
+ }
+
+ RootNode targetRoot = ensureTargetRoot(targetBom, targetModel, templateRoot, targetStructures);
+ int copiedChildren = copyTemplateChildren(templateBom, templateRoot, templateChildren, targetBom, targetRoot.getNode());
+
+ copiedBomCount++;
+ insertedStructureCount += copiedChildren + (targetRoot.isInserted() ? 1 : 0);
+ }
+
+ return CopySummary.copied(
+ productId,
+ productModels.size(),
+ templateBom.getId(),
+ templateBom.getBomNo(),
+ bomList.size(),
+ copiedBomCount,
+ skippedBomCount,
+ insertedStructureCount
+ );
+ }
+
+ private Map<Integer, List<ProductStructure>> loadStructureMap(List<ProductBom> bomList) {
+ List<Integer> bomIds = bomList.stream()
+ .map(ProductBom::getId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ if (bomIds.isEmpty()) {
+ return Collections.emptyMap();
+ }
+
+ List<ProductStructure> structures = productStructureMapper.selectList(
+ Wrappers.<ProductStructure>lambdaQuery()
+ .in(ProductStructure::getBomId, bomIds)
+ .orderByAsc(ProductStructure::getId)
+ );
+
+ Map<Integer, List<ProductStructure>> structureMap = new HashMap<>();
+ for (ProductStructure structure : structures) {
+ structureMap.computeIfAbsent(structure.getBomId(), key -> new ArrayList<>()).add(structure);
+ }
+ return structureMap;
+ }
+
+ private ProductBom findTemplateBomOrNull(List<ProductBom> bomList, Map<Integer, List<ProductStructure>> structureMap) {
+ return bomList.stream()
+ .filter(item -> hasChildNodes(structureMap.getOrDefault(item.getId(), Collections.emptyList())))
+ .max(Comparator.comparingInt(item -> childNodeCount(structureMap.getOrDefault(item.getId(), Collections.emptyList()))))
+ .orElse(null);
+ }
+
+ private int childNodeCount(List<ProductStructure> structures) {
+ if (structures == null) {
+ return 0;
+ }
+ int count = 0;
+ for (ProductStructure structure : structures) {
+ if (!isRoot(structure)) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private boolean hasChildNodes(List<ProductStructure> structures) {
+ return childNodeCount(structures) > 0;
+ }
+
+ private ProductStructure requireSingleRoot(ProductBom bom, List<ProductStructure> structures) {
+ List<ProductStructure> roots = findRoots(structures);
+ if (roots.size() != 1) {
+ throw new IllegalStateException("BOM鏍硅妭鐐规暟閲忓紓甯革紝bomId=" + bom.getId() + "锛宺ootCount=" + roots.size());
+ }
+ return roots.get(0);
+ }
+
+ private RootNode ensureTargetRoot(ProductBom targetBom,
+ ProductModel targetModel,
+ ProductStructure templateRoot,
+ List<ProductStructure> targetStructures) {
+ List<ProductStructure> roots = findRoots(targetStructures);
+ if (roots.size() > 1) {
+ throw new IllegalStateException("鐩爣BOM鏍硅妭鐐规暟閲忓紓甯革紝bomId=" + targetBom.getId() + "锛宺ootCount=" + roots.size());
+ }
+ if (roots.size() == 1) {
+ return new RootNode(roots.get(0), false);
+ }
+
+ ProductStructure targetRoot = new ProductStructure();
+ targetRoot.setParentId(null);
+ targetRoot.setBomId(targetBom.getId());
+ targetRoot.setProductModelId(targetBom.getProductModelId());
+ targetRoot.setProcessId(templateRoot.getProcessId());
+ targetRoot.setUnitQuantity(templateRoot.getUnitQuantity() == null ? BigDecimal.ONE : templateRoot.getUnitQuantity());
+ targetRoot.setDemandedQuantity(templateRoot.getDemandedQuantity());
+ targetRoot.setUnit(targetModel.getUnit());
+ targetRoot.setTenantId(firstNotNull(targetBom.getTenantId(), targetModel.getTenantId(), templateRoot.getTenantId()));
+ productStructureMapper.insert(targetRoot);
+ return new RootNode(targetRoot, true);
+ }
+
+ private int copyTemplateChildren(ProductBom templateBom,
+ ProductStructure templateRoot,
+ List<ProductStructure> templateChildren,
+ ProductBom targetBom,
+ ProductStructure targetRoot) {
+ Map<Long, Long> idMapping = new HashMap<>();
+ idMapping.put(templateRoot.getId(), targetRoot.getId());
+
+ List<NodePair> insertedNodes = new ArrayList<>();
+ for (ProductStructure sourceNode : templateChildren) {
+ ProductStructure copiedNode = new ProductStructure();
+ copiedNode.setParentId(null);
+ copiedNode.setProductModelId(sourceNode.getProductModelId());
+ copiedNode.setProcessId(sourceNode.getProcessId());
+ copiedNode.setUnitQuantity(sourceNode.getUnitQuantity());
+ copiedNode.setDemandedQuantity(sourceNode.getDemandedQuantity());
+ copiedNode.setUnit(sourceNode.getUnit());
+ copiedNode.setTenantId(firstNotNull(targetBom.getTenantId(), sourceNode.getTenantId()));
+ copiedNode.setBomId(targetBom.getId());
+
+ productStructureMapper.insert(copiedNode);
+ idMapping.put(sourceNode.getId(), copiedNode.getId());
+ insertedNodes.add(new NodePair(sourceNode, copiedNode));
+ }
+
+ for (NodePair insertedNode : insertedNodes) {
+ Long sourceParentId = insertedNode.getSourceNode().getParentId();
+ Long newParentId = idMapping.get(sourceParentId);
+ if (newParentId == null) {
+ throw new IllegalStateException("妯℃澘BOM瀛樺湪鏃犳硶鏄犲皠鐨勭埗鑺傜偣锛宼emplateBomId=" + templateBom.getId()
+ + "锛宻ourceNodeId=" + insertedNode.getSourceNode().getId()
+ + "锛宻ourceParentId=" + sourceParentId);
+ }
+
+ ProductStructure copiedNode = insertedNode.getCopiedNode();
+ copiedNode.setParentId(newParentId);
+ productStructureMapper.updateById(copiedNode);
+ }
+
+ return insertedNodes.size();
+ }
+
+ private List<ProductStructure> findRoots(List<ProductStructure> structures) {
+ if (structures == null) {
+ return Collections.emptyList();
+ }
+ return structures.stream()
+ .filter(this::isRoot)
+ .collect(Collectors.toList());
+ }
+
+ private boolean isRoot(ProductStructure structure) {
+ return structure.getParentId() == null || Long.valueOf(0L).equals(structure.getParentId());
+ }
+
+ private Long firstNotNull(Long first, Long second) {
+ return first != null ? first : second;
+ }
+
+ private Long firstNotNull(Long first, Long second, Long third) {
+ if (first != null) {
+ return first;
+ }
+ return second != null ? second : third;
+ }
+
+ private void printProductSummary(CopySummary summary) {
+ if (summary.isProductSkipped()) {
+ System.out.printf(
+ "璺宠繃浜у搧鍒嗙被锛歱roductId=%s锛岃鏍兼暟=%s锛孊OM鎬绘暟=%s锛屽師鍥�=%s%n",
+ summary.getProductId(),
+ summary.getProductModelCount(),
+ summary.getTotalBomCount(),
+ summary.getSkipReason()
+ );
+ return;
+ }
+
+ System.out.printf(
+ "澶勭悊浜у搧鍒嗙被锛歱roductId=%s锛屾ā鏉緽OM=%s(%s)锛岃鏍兼暟=%s锛孊OM鎬绘暟=%s锛屽凡琛ラ綈BOM=%s锛岃烦杩嘊OM=%s锛屾柊澧炵粨鏋勮妭鐐�=%s%n",
+ summary.getProductId(),
+ summary.getTemplateBomNo(),
+ summary.getTemplateBomId(),
+ summary.getProductModelCount(),
+ summary.getTotalBomCount(),
+ summary.getCopiedBomCount(),
+ summary.getSkippedBomCount(),
+ summary.getInsertedStructureCount()
+ );
+ }
+
+ private void printBatchSummary(List<CopySummary> summaries) {
+ int productCount = summaries.size();
+ int skippedProductCount = 0;
+ int totalBomCount = 0;
+ int copiedBomCount = 0;
+ int skippedBomCount = 0;
+ int insertedStructureCount = 0;
+
+ for (CopySummary summary : summaries) {
+ if (summary.isProductSkipped()) {
+ skippedProductCount++;
+ }
+ totalBomCount += summary.getTotalBomCount();
+ copiedBomCount += summary.getCopiedBomCount();
+ skippedBomCount += summary.getSkippedBomCount();
+ insertedStructureCount += summary.getInsertedStructureCount();
+ }
+
+ System.out.printf(
+ "BOM缁撴瀯鎵归噺澶嶅埗瀹屾垚锛氫骇鍝佸垎绫绘暟=%s锛屽凡澶勭悊鍒嗙被=%s锛岃烦杩囧垎绫�=%s锛孊OM鎬绘暟=%s锛屽凡琛ラ綈BOM=%s锛岃烦杩嘊OM=%s锛屾柊澧炵粨鏋勮妭鐐�=%s%n",
+ productCount,
+ productCount - skippedProductCount,
+ skippedProductCount,
+ totalBomCount,
+ copiedBomCount,
+ skippedBomCount,
+ insertedStructureCount
+ );
+ }
+
+ private static class RootNode {
+ private final ProductStructure node;
+ private final boolean inserted;
+
+ private RootNode(ProductStructure node, boolean inserted) {
+ this.node = node;
+ this.inserted = inserted;
+ }
+
+ private ProductStructure getNode() {
+ return node;
+ }
+
+ private boolean isInserted() {
+ return inserted;
+ }
+ }
+
+ private static class NodePair {
+ private final ProductStructure sourceNode;
+ private final ProductStructure copiedNode;
+
+ private NodePair(ProductStructure sourceNode, ProductStructure copiedNode) {
+ this.sourceNode = sourceNode;
+ this.copiedNode = copiedNode;
+ }
+
+ private ProductStructure getSourceNode() {
+ return sourceNode;
+ }
+
+ private ProductStructure getCopiedNode() {
+ return copiedNode;
+ }
+ }
+
+ private static class CopySummary {
+ private final Long productId;
+ private final int productModelCount;
+ private final Integer templateBomId;
+ private final String templateBomNo;
+ private final int totalBomCount;
+ private final int copiedBomCount;
+ private final int skippedBomCount;
+ private final int insertedStructureCount;
+ private final String skipReason;
+
+ private CopySummary(Long productId,
+ int productModelCount,
+ Integer templateBomId,
+ String templateBomNo,
+ int totalBomCount,
+ int copiedBomCount,
+ int skippedBomCount,
+ int insertedStructureCount,
+ String skipReason) {
+ this.productId = productId;
+ this.productModelCount = productModelCount;
+ this.templateBomId = templateBomId;
+ this.templateBomNo = templateBomNo;
+ this.totalBomCount = totalBomCount;
+ this.copiedBomCount = copiedBomCount;
+ this.skippedBomCount = skippedBomCount;
+ this.insertedStructureCount = insertedStructureCount;
+ this.skipReason = skipReason;
+ }
+
+ private static CopySummary copied(Long productId,
+ int productModelCount,
+ Integer templateBomId,
+ String templateBomNo,
+ int totalBomCount,
+ int copiedBomCount,
+ int skippedBomCount,
+ int insertedStructureCount) {
+ return new CopySummary(
+ productId,
+ productModelCount,
+ templateBomId,
+ templateBomNo,
+ totalBomCount,
+ copiedBomCount,
+ skippedBomCount,
+ insertedStructureCount,
+ null
+ );
+ }
+
+ private static CopySummary skipped(Long productId, int productModelCount, int totalBomCount, String skipReason) {
+ return new CopySummary(
+ productId,
+ productModelCount,
+ null,
+ null,
+ totalBomCount,
+ 0,
+ totalBomCount,
+ 0,
+ skipReason
+ );
+ }
+
+ private Long getProductId() {
+ return productId;
+ }
+
+ private int getProductModelCount() {
+ return productModelCount;
+ }
+
+ private Integer getTemplateBomId() {
+ return templateBomId;
+ }
+
+ private String getTemplateBomNo() {
+ return templateBomNo;
+ }
+
+ private int getTotalBomCount() {
+ return totalBomCount;
+ }
+
+ private int getCopiedBomCount() {
+ return copiedBomCount;
+ }
+
+ private int getSkippedBomCount() {
+ return skippedBomCount;
+ }
+
+ private int getInsertedStructureCount() {
+ return insertedStructureCount;
+ }
+
+ private String getSkipReason() {
+ return skipReason;
+ }
+
+ private boolean isProductSkipped() {
+ return skipReason != null;
+ }
+ }
+}
diff --git a/src/test/java/com/ruoyi/production/ProcessRouteItemCopyTest.java b/src/test/java/com/ruoyi/production/ProcessRouteItemCopyTest.java
new file mode 100644
index 0000000..bedfc31
--- /dev/null
+++ b/src/test/java/com/ruoyi/production/ProcessRouteItemCopyTest.java
@@ -0,0 +1,352 @@
+package com.ruoyi.production;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.ruoyi.basic.mapper.ProductModelMapper;
+import com.ruoyi.basic.pojo.ProductModel;
+import com.ruoyi.production.mapper.ProcessRouteItemMapper;
+import com.ruoyi.production.mapper.ProcessRouteMapper;
+import com.ruoyi.production.pojo.ProcessRoute;
+import com.ruoyi.production.pojo.ProcessRouteItem;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.Rollback;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * 宸ヨ壓璺嚎椤圭洰琛ラ綈娴嬭瘯銆�
+ */
+@SpringBootTest
+public class ProcessRouteItemCopyTest {
+
+ @Autowired
+ private ProductModelMapper productModelMapper;
+
+ @Autowired
+ private ProcessRouteMapper processRouteMapper;
+
+ @Autowired
+ private ProcessRouteItemMapper processRouteItemMapper;
+
+ @Test
+ @Rollback(false)
+ @Transactional(rollbackFor = Exception.class)
+ public void copyAllProcessRouteItemsByProductId() {
+ List<ProductModel> allProductModels = productModelMapper.selectList(
+ Wrappers.<ProductModel>lambdaQuery()
+ .isNotNull(ProductModel::getProductId)
+ .orderByAsc(ProductModel::getProductId)
+ .orderByAsc(ProductModel::getId)
+ );
+ if (CollectionUtils.isEmpty(allProductModels)) {
+ throw new IllegalStateException("鏈煡璇㈠埌浠讳綍浜у搧瑙勬牸");
+ }
+
+ Map<Long, List<ProductModel>> productModelGroups = allProductModels.stream()
+ .collect(Collectors.groupingBy(ProductModel::getProductId, LinkedHashMap::new, Collectors.toList()));
+
+ List<CopySummary> summaries = new ArrayList<>();
+ for (Map.Entry<Long, List<ProductModel>> entry : productModelGroups.entrySet()) {
+ CopySummary summary = copyProcessRouteItems(entry.getKey(), entry.getValue());
+ summaries.add(summary);
+ printProductSummary(summary);
+ }
+
+ printBatchSummary(summaries);
+ }
+
+ private CopySummary copyProcessRouteItems(Long productId, List<ProductModel> productModels) {
+ if (CollectionUtils.isEmpty(productModels)) {
+ return CopySummary.skipped(productId, 0, 0, "鏈煡璇㈠埌浜у搧澶х被瀵瑰簲鐨勮鏍�");
+ }
+
+ Map<Long, ProductModel> productModelMap = productModels.stream()
+ .collect(Collectors.toMap(ProductModel::getId, item -> item, (left, right) -> left, LinkedHashMap::new));
+ List<Long> productModelIds = new ArrayList<>(productModelMap.keySet());
+
+ List<ProcessRoute> routeList = processRouteMapper.selectList(
+ Wrappers.<ProcessRoute>lambdaQuery()
+ .in(ProcessRoute::getProductModelId, productModelIds)
+ .orderByAsc(ProcessRoute::getId)
+ );
+ if (CollectionUtils.isEmpty(routeList)) {
+ return CopySummary.skipped(productId, productModels.size(), 0, "鏈煡璇㈠埌浜у搧澶х被瀵瑰簲鐨勫伐鑹鸿矾绾�");
+ }
+
+ Map<Long, List<ProcessRouteItem>> routeItemMap = loadRouteItemMap(routeList);
+ ProcessRoute templateRoute = findTemplateRouteOrNull(routeList, routeItemMap);
+ if (templateRoute == null) {
+ return CopySummary.skipped(productId, productModels.size(), routeList.size(), "褰撳墠浜у搧澶х被涓嬫病鏈夊彲浣滀负妯℃澘鐨勫畬鏁磋矾绾块」鐩�");
+ }
+
+ List<ProcessRouteItem> templateItems = routeItemMap.getOrDefault(templateRoute.getId(), Collections.emptyList())
+ .stream()
+ .sorted(Comparator
+ .comparing(ProcessRouteItem::getDragSort, Comparator.nullsLast(Integer::compareTo))
+ .thenComparing(ProcessRouteItem::getId))
+ .collect(Collectors.toList());
+
+ int copiedRouteCount = 0;
+ int skippedRouteCount = 0;
+ int insertedRouteItemCount = 0;
+
+ for (ProcessRoute targetRoute : routeList) {
+ if (Objects.equals(templateRoute.getId(), targetRoute.getId())) {
+ skippedRouteCount++;
+ continue;
+ }
+
+ List<ProcessRouteItem> targetItems = routeItemMap.getOrDefault(targetRoute.getId(), Collections.emptyList());
+ if (!targetItems.isEmpty()) {
+ skippedRouteCount++;
+ continue;
+ }
+
+ int copiedItems = copyTemplateItems(templateItems, targetRoute);
+ copiedRouteCount++;
+ insertedRouteItemCount += copiedItems;
+ }
+
+ return CopySummary.copied(
+ productId,
+ productModels.size(),
+ templateRoute.getId(),
+ templateRoute.getProcessRouteCode(),
+ routeList.size(),
+ copiedRouteCount,
+ skippedRouteCount,
+ insertedRouteItemCount
+ );
+ }
+
+ private Map<Long, List<ProcessRouteItem>> loadRouteItemMap(List<ProcessRoute> routeList) {
+ List<Long> routeIds = routeList.stream()
+ .map(ProcessRoute::getId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ if (routeIds.isEmpty()) {
+ return Collections.emptyMap();
+ }
+
+ List<ProcessRouteItem> routeItems = processRouteItemMapper.selectList(
+ Wrappers.<ProcessRouteItem>lambdaQuery()
+ .in(ProcessRouteItem::getRouteId, routeIds)
+ .orderByAsc(ProcessRouteItem::getRouteId)
+ .orderByAsc(ProcessRouteItem::getDragSort)
+ .orderByAsc(ProcessRouteItem::getId)
+ );
+
+ Map<Long, List<ProcessRouteItem>> routeItemMap = new HashMap<>();
+ for (ProcessRouteItem routeItem : routeItems) {
+ routeItemMap.computeIfAbsent(routeItem.getRouteId(), key -> new ArrayList<>()).add(routeItem);
+ }
+ return routeItemMap;
+ }
+
+ private ProcessRoute findTemplateRouteOrNull(List<ProcessRoute> routeList,
+ Map<Long, List<ProcessRouteItem>> routeItemMap) {
+ return routeList.stream()
+ .filter(item -> routeItemCount(routeItemMap.getOrDefault(item.getId(), Collections.emptyList())) > 0)
+ .max(Comparator.comparingInt(item -> routeItemCount(routeItemMap.getOrDefault(item.getId(), Collections.emptyList()))))
+ .orElse(null);
+ }
+
+ private int routeItemCount(List<ProcessRouteItem> routeItems) {
+ return routeItems == null ? 0 : routeItems.size();
+ }
+
+ private int copyTemplateItems(List<ProcessRouteItem> templateItems, ProcessRoute targetRoute) {
+ int insertedCount = 0;
+ for (int i = 0; i < templateItems.size(); i++) {
+ ProcessRouteItem sourceItem = templateItems.get(i);
+ ProcessRouteItem copiedItem = new ProcessRouteItem();
+ copiedItem.setRouteId(targetRoute.getId());
+ copiedItem.setProductModelId(sourceItem.getProductModelId());
+ copiedItem.setProcessId(sourceItem.getProcessId());
+ copiedItem.setTenantId(firstNotNull(targetRoute.getTenantId(), sourceItem.getTenantId()));
+ copiedItem.setDragSort(sourceItem.getDragSort() == null ? i + 1 : sourceItem.getDragSort());
+ copiedItem.setIsQuality(sourceItem.getIsQuality());
+
+ processRouteItemMapper.insert(copiedItem);
+ insertedCount++;
+ }
+ return insertedCount;
+ }
+
+ private Long firstNotNull(Long first, Long second) {
+ return first != null ? first : second;
+ }
+
+ private void printProductSummary(CopySummary summary) {
+ if (summary.isProductSkipped()) {
+ System.out.printf(
+ "璺宠繃浜у搧鍒嗙被锛歱roductId=%s锛岃鏍兼暟=%s锛屽伐鑹鸿矾绾挎�绘暟=%s锛屽師鍥�=%s%n",
+ summary.getProductId(),
+ summary.getProductModelCount(),
+ summary.getTotalRouteCount(),
+ summary.getSkipReason()
+ );
+ return;
+ }
+
+ System.out.printf(
+ "澶勭悊浜у搧鍒嗙被锛歱roductId=%s锛屾ā鏉垮伐鑹鸿矾绾�=%s(%s)锛岃鏍兼暟=%s锛屽伐鑹鸿矾绾挎�绘暟=%s锛屽凡琛ラ綈璺嚎=%s锛岃烦杩囪矾绾�=%s锛屾柊澧炶矾绾块」鐩�=%s%n",
+ summary.getProductId(),
+ summary.getTemplateRouteCode(),
+ summary.getTemplateRouteId(),
+ summary.getProductModelCount(),
+ summary.getTotalRouteCount(),
+ summary.getCopiedRouteCount(),
+ summary.getSkippedRouteCount(),
+ summary.getInsertedRouteItemCount()
+ );
+ }
+
+ private void printBatchSummary(List<CopySummary> summaries) {
+ int productCount = summaries.size();
+ int skippedProductCount = 0;
+ int totalRouteCount = 0;
+ int copiedRouteCount = 0;
+ int skippedRouteCount = 0;
+ int insertedRouteItemCount = 0;
+
+ for (CopySummary summary : summaries) {
+ if (summary.isProductSkipped()) {
+ skippedProductCount++;
+ }
+ totalRouteCount += summary.getTotalRouteCount();
+ copiedRouteCount += summary.getCopiedRouteCount();
+ skippedRouteCount += summary.getSkippedRouteCount();
+ insertedRouteItemCount += summary.getInsertedRouteItemCount();
+ }
+
+ System.out.printf(
+ "宸ヨ壓璺嚎椤圭洰鎵归噺澶嶅埗瀹屾垚锛氫骇鍝佸垎绫绘暟=%s锛屽凡澶勭悊鍒嗙被=%s锛岃烦杩囧垎绫�=%s锛屽伐鑹鸿矾绾挎�绘暟=%s锛屽凡琛ラ綈璺嚎=%s锛岃烦杩囪矾绾�=%s锛屾柊澧炶矾绾块」鐩�=%s%n",
+ productCount,
+ productCount - skippedProductCount,
+ skippedProductCount,
+ totalRouteCount,
+ copiedRouteCount,
+ skippedRouteCount,
+ insertedRouteItemCount
+ );
+ }
+
+ private static class CopySummary {
+ private final Long productId;
+ private final int productModelCount;
+ private final Long templateRouteId;
+ private final String templateRouteCode;
+ private final int totalRouteCount;
+ private final int copiedRouteCount;
+ private final int skippedRouteCount;
+ private final int insertedRouteItemCount;
+ private final String skipReason;
+
+ private CopySummary(Long productId,
+ int productModelCount,
+ Long templateRouteId,
+ String templateRouteCode,
+ int totalRouteCount,
+ int copiedRouteCount,
+ int skippedRouteCount,
+ int insertedRouteItemCount,
+ String skipReason) {
+ this.productId = productId;
+ this.productModelCount = productModelCount;
+ this.templateRouteId = templateRouteId;
+ this.templateRouteCode = templateRouteCode;
+ this.totalRouteCount = totalRouteCount;
+ this.copiedRouteCount = copiedRouteCount;
+ this.skippedRouteCount = skippedRouteCount;
+ this.insertedRouteItemCount = insertedRouteItemCount;
+ this.skipReason = skipReason;
+ }
+
+ private static CopySummary copied(Long productId,
+ int productModelCount,
+ Long templateRouteId,
+ String templateRouteCode,
+ int totalRouteCount,
+ int copiedRouteCount,
+ int skippedRouteCount,
+ int insertedRouteItemCount) {
+ return new CopySummary(
+ productId,
+ productModelCount,
+ templateRouteId,
+ templateRouteCode,
+ totalRouteCount,
+ copiedRouteCount,
+ skippedRouteCount,
+ insertedRouteItemCount,
+ null
+ );
+ }
+
+ private static CopySummary skipped(Long productId, int productModelCount, int totalRouteCount, String skipReason) {
+ return new CopySummary(
+ productId,
+ productModelCount,
+ null,
+ null,
+ totalRouteCount,
+ 0,
+ totalRouteCount,
+ 0,
+ skipReason
+ );
+ }
+
+ private Long getProductId() {
+ return productId;
+ }
+
+ private int getProductModelCount() {
+ return productModelCount;
+ }
+
+ private Long getTemplateRouteId() {
+ return templateRouteId;
+ }
+
+ private String getTemplateRouteCode() {
+ return templateRouteCode;
+ }
+
+ private int getTotalRouteCount() {
+ return totalRouteCount;
+ }
+
+ private int getCopiedRouteCount() {
+ return copiedRouteCount;
+ }
+
+ private int getSkippedRouteCount() {
+ return skippedRouteCount;
+ }
+
+ private int getInsertedRouteItemCount() {
+ return insertedRouteItemCount;
+ }
+
+ private String getSkipReason() {
+ return skipReason;
+ }
+
+ private boolean isProductSkipped() {
+ return skipReason != null;
+ }
+ }
+}
--
Gitblit v1.9.3