From 9cc2ddd5012a448d6187250121ba7f0cd0c5663b Mon Sep 17 00:00:00 2001
From: liyong <18434998025@163.com>
Date: 星期一, 10 八月 2026 10:17:25 +0800
Subject: [PATCH] 下发报错修改
---
src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 217 insertions(+), 15 deletions(-)
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
index 6a30baf..8278148 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -23,6 +23,7 @@
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.production.service.ProductionBomStructureService;
+import com.ruoyi.production.util.TaskPlanQuantityUtil;
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
import com.ruoyi.technology.mapper.TechnologyParamMapper;
@@ -30,6 +31,7 @@
import com.ruoyi.technology.pojo.TechnologyOperationParam;
import com.ruoyi.technology.pojo.TechnologyParam;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -48,6 +50,7 @@
* @author 鑺杞欢锛堟睙鑻忥級鏈夐檺鍏徃
* @since 2026-04-21 03:55:52
*/
+@Slf4j
@Service
@RequiredArgsConstructor()
public class ProductionBomStructureServiceImpl extends ServiceImpl<ProductionBomStructureMapper, ProductionBomStructure> implements ProductionBomStructureService {
@@ -136,6 +139,9 @@
entity.setProductionOrderBomId(orderBomId);
if (item.getId() == null) {
entity.setParentId(null);
+ // 鏂板鑺傜偣鐨勯渶姹傞噺鐢卞悗绔寜BOM鏍戝舰缁撴瀯閲嶆柊璁$畻锛屼笉娓呯┖鍙兘瀵艰嚧鍓嶇浼犵殑鍊兼孩鍑�
+ entity.setDemandedQuantity(null);
+ entity.setId(null);
insertList.add(entity);
tempEntityMap.put(item.getTempId(), entity);
} else {
@@ -145,6 +151,11 @@
// 鎵归噺鏂板锛屾嬁鍒版暟鎹簱鐢熸垚鐨勭湡瀹濱D
if (!insertList.isEmpty()) {
+ for (ProductionBomStructure entity : insertList) {
+ log.info("鍑嗗鏂板BOM缁撴瀯鑺傜偣: productModelId={}, technologyOperationId={}, unitQuantity={}, demandedQuantity={}, unit={}",
+ entity.getProductModelId(), entity.getTechnologyOperationId(),
+ entity.getUnitQuantity(), entity.getDemandedQuantity(), entity.getUnit());
+ }
this.saveBatch(insertList);
}
@@ -215,21 +226,76 @@
if (structureList == null || structureList.isEmpty()) {
return;
}
- List<ProductionBomStructure> updateList = new ArrayList<>();
+ log.info("寮�濮嬫寜BOM鏍戝舰缁撴瀯璁$畻闇�姹傞噺锛岃鍗曟暟閲�={}, BOM鑺傜偣鎬绘暟={}", orderQuantity, structureList.size());
+ // 鏋勫缓 id 鈫� structure 鏄犲皠鍜� parentId 鈫� children 鏄犲皠
+ Map<Long, ProductionBomStructure> structureById = new HashMap<>();
+ Map<Long, List<ProductionBomStructure>> childrenMap = new LinkedHashMap<>();
for (ProductionBomStructure structure : structureList) {
if (structure == null || structure.getId() == null) {
continue;
}
- BigDecimal demandedQuantity = defaultDecimal(structure.getUnitQuantity()).multiply(orderQuantity);
- if (compareDecimal(structure.getDemandedQuantity(), demandedQuantity) == 0) {
+ structureById.put(structure.getId(), structure);
+ Long parentId = structure.getParentId();
+ childrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(structure);
+ }
+
+ List<ProductionBomStructure> updateList = new ArrayList<>();
+ // 浠庢牴鑺傜偣寮�濮嬶紝鎸夋爲褰㈠眰绾ч�愬眰璁$畻闇�姹傞噺
+ // 鏍硅妭鐐� parentId 涓� null 鎴� 0
+ Deque<Long> queue = new ArrayDeque<>();
+ List<ProductionBomStructure> rootNodes = childrenMap.get(null);
+ if (rootNodes != null) {
+ for (ProductionBomStructure root : rootNodes) {
+ queue.add(root.getId());
+ }
+ }
+ // parentId=0 鐨勪篃瑙嗕负鏍硅妭鐐�
+ List<ProductionBomStructure> zeroParentNodes = childrenMap.get(0L);
+ if (zeroParentNodes != null) {
+ for (ProductionBomStructure root : zeroParentNodes) {
+ if (!queue.contains(root.getId())) {
+ queue.add(root.getId());
+ }
+ }
+ }
+
+ while (!queue.isEmpty()) {
+ Long nodeId = queue.poll();
+ ProductionBomStructure node = structureById.get(nodeId);
+ if (node == null) {
continue;
}
+ // 璁$畻褰撳墠鑺傜偣鐨勯渶姹傛暟閲� = 鐖惰妭鐐归渶姹傞噺 脳 鑷韩 unitQuantity
+ // 鏍硅妭鐐癸細闇�姹傞噺 = 璁㈠崟鏁伴噺 脳 unitQuantity
+ BigDecimal parentDemandedQuantity = orderQuantity;
+ Long parentId = node.getParentId();
+ if (parentId != null && parentId != 0L) {
+ ProductionBomStructure parent = structureById.get(parentId);
+ if (parent != null && parent.getDemandedQuantity() != null) {
+ parentDemandedQuantity = parent.getDemandedQuantity();
+ }
+ }
+ BigDecimal demandedQuantity = parentDemandedQuantity.multiply(defaultDecimal(node.getUnitQuantity()));
+
+ log.info("BOM闇�姹傞噺璁$畻: nodeId={}, parentId={}, parentDemandedQuantity={}, unitQuantity={}, demandedQuantity={}",
+ node.getId(), node.getParentId(), parentDemandedQuantity,
+ defaultDecimal(node.getUnitQuantity()), demandedQuantity);
+
ProductionBomStructure update = new ProductionBomStructure();
- update.setId(structure.getId());
+ update.setId(node.getId());
update.setDemandedQuantity(demandedQuantity);
updateList.add(update);
- structure.setDemandedQuantity(demandedQuantity);
+ node.setDemandedQuantity(demandedQuantity);
+
+ // 灏嗗瓙鑺傜偣鍔犲叆闃熷垪
+ List<ProductionBomStructure> children = childrenMap.get(nodeId);
+ if (children != null) {
+ for (ProductionBomStructure child : children) {
+ queue.add(child.getId());
+ }
+ }
}
+
if (!updateList.isEmpty()) {
this.updateBatchById(updateList);
}
@@ -259,7 +325,7 @@
.filter(item -> item != null && item.getId() != null)
.collect(Collectors.toMap(ProductionOrderRoutingOperation::getId, item -> item, (left, right) -> left));
// Keep task plan quantities aligned with the same order BOM snapshot demand used during snapshot creation.
- Map<String, BigDecimal> demandedQuantityMap = buildOperationDemandedQuantityMap(structureList, rootProductModelId);
+ Map<String, BigDecimal> demandedQuantityMap = TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(structureList, rootProductModelId);
for (ProductionOperationTask task : taskList) {
if (task == null || task.getId() == null || task.getProductionOrderRoutingOperationId() == null) {
continue;
@@ -378,17 +444,32 @@
Map<Long, ProductionBomStructure> structureById = structureList.stream()
.filter(item -> item != null && item.getId() != null)
.collect(Collectors.toMap(ProductionBomStructure::getId, item -> item, (left, right) -> left));
- Map<String, ProductionBomStructure> uniqueOperationMap = new LinkedHashMap<>();
- for (ProductionBomStructure bomStructure : structureList) {
- if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) {
- continue;
+
+ // 鏋勫缓鐖�-瀛愭槧灏勫叧绯�
+ Map<Long, List<ProductionBomStructure>> treeMap = buildParentChildMap(structureList);
+
+ // 浣跨敤鍚庡簭閬嶅巻鏋勫缓鎿嶄綔鍒楄〃锛堝厛瀛愬悗鐖讹紝纭繚宸ヨ壓璺嚎椤哄簭姝g‘锛�
+ // 浣跨敤娣卞害浣滀负鎺掑簭渚濇嵁鐨勮緟鍔╃粨鏋�
+ Map<String, ProductionBomStructure> operationMap = new LinkedHashMap<>();
+ Map<String, Integer> depthMap = new HashMap<>();
+ buildOperationListPostOrderWithDepth(null, treeMap, operationMap, depthMap, structureById, rootProductModelId, 1);
+
+ // 鎸夋繁搴︽帓搴忥紝娣卞害澶х殑鎺掑墠闈�
+ List<Map.Entry<String, ProductionBomStructure>> sortedEntries = new ArrayList<>(operationMap.entrySet());
+ sortedEntries.sort((a, b) -> {
+ int depthCompare = Integer.compare(
+ depthMap.getOrDefault(b.getKey(), 0),
+ depthMap.getOrDefault(a.getKey(), 0));
+ if (depthCompare != 0) {
+ return depthCompare;
}
- Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
- uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(bomStructure, outputProductModelId), bomStructure);
- }
+ return 0;
+ });
+
List<ProductionOrderRoutingOperation> desiredOperationList = new ArrayList<>();
int dragSort = 1;
- for (ProductionBomStructure bomStructure : uniqueOperationMap.values()) {
+ for (Map.Entry<String, ProductionBomStructure> entry : sortedEntries) {
+ ProductionBomStructure bomStructure = entry.getValue();
Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId);
TechnologyOperation technologyOperation = getTechnologyOperation(bomStructure.getTechnologyOperationId());
ProductionOrderRoutingOperation routingOperation = new ProductionOrderRoutingOperation();
@@ -402,6 +483,127 @@
desiredOperationList.add(routingOperation);
}
return desiredOperationList;
+ }
+
+ private void buildOperationListPostOrderWithDepth(Long parentId,
+ Map<Long, List<ProductionBomStructure>> treeMap,
+ Map<String, ProductionBomStructure> operationMap,
+ Map<String, Integer> depthMap,
+ Map<Long, ProductionBomStructure> structureById,
+ Long rootProductModelId,
+ int currentDepth) {
+ List<ProductionBomStructure> children = treeMap.get(parentId);
+ if (children == null || children.isEmpty()) {
+ return;
+ }
+ for (ProductionBomStructure child : children) {
+ // 鍏堥�掑綊澶勭悊瀛愯妭鐐�
+ buildOperationListPostOrderWithDepth(child.getId(), treeMap, operationMap, depthMap, structureById, rootProductModelId, currentDepth + 1);
+
+ // 鍐嶅鐞嗗綋鍓嶈妭鐐�
+ if (child.getTechnologyOperationId() != null) {
+ Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
+ String key = buildBomOperationDedupKey(child, outputProductModelId);
+ // 淇濈暀娣卞害鏈�澶х殑鎿嶄綔
+ Integer existingDepth = depthMap.get(key);
+ if (existingDepth == null || currentDepth > existingDepth) {
+ operationMap.put(key, child);
+ depthMap.put(key, currentDepth);
+ }
+ }
+ }
+ }
+
+ private Map<Long, List<ProductionBomStructure>> buildParentChildMap(List<ProductionBomStructure> structureList) {
+ Map<Long, List<ProductionBomStructure>> treeMap = new LinkedHashMap<>();
+ Map<Long, ProductionBomStructure> structureById = new HashMap<>();
+
+ // 鏋勫缓鐖�-瀛愭槧灏勫拰ID鏄犲皠
+ for (ProductionBomStructure structure : structureList) {
+ if (structure == null) continue;
+ Long parentId = structure.getParentId();
+ treeMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(structure);
+ if (structure.getId() != null) {
+ structureById.put(structure.getId(), structure);
+ }
+ }
+
+ // 璁$畻姣忎釜鑺傜偣鐨勬繁搴︼紙浠庢牴鑺傜偣鍒板綋鍓嶈妭鐐圭殑璺濈锛屾牴鑺傜偣娣卞害涓�1锛�
+ Map<Long, Integer> depthMap = new HashMap<>();
+ for (ProductionBomStructure structure : structureList) {
+ if (structure == null || structure.getId() == null) continue;
+ computeDepthFromRoot(structure.getId(), structureById, depthMap);
+ }
+
+ // 瀵规瘡涓埗鑺傜偣涓嬬殑瀛愯妭鐐规寜娣卞害鍊掑簭鎺掑簭锛堟渶娣卞眰鐨勪紭鍏堬級
+ for (Map.Entry<Long, List<ProductionBomStructure>> entry : treeMap.entrySet()) {
+ List<ProductionBomStructure> children = entry.getValue();
+ children.sort((a, b) -> {
+ // 浼樺厛鎸夋繁搴︽帓搴忥紝娣卞害澶х殑鎺掑墠闈紙鏈�娣卞眰浼樺厛锛�
+ int depthCompare = Integer.compare(
+ depthMap.getOrDefault(b.getId(), 0),
+ depthMap.getOrDefault(a.getId(), 0));
+ if (depthCompare != 0) {
+ return depthCompare;
+ }
+ // 娣卞害鐩稿悓鏃舵寜ID鎺掑簭淇濊瘉绋冲畾鎬�
+ return Long.compare(a.getId(), b.getId());
+ });
+ }
+
+ return treeMap;
+ }
+
+ /**
+ * 璁$畻鑺傜偣娣卞害锛堜粠鏍硅妭鐐瑰埌褰撳墠鑺傜偣鐨勮窛绂伙級
+ * 鏍硅妭鐐规繁搴︿负1锛屾瘡鍚戜笅涓�灞傛繁搴﹀姞1
+ */
+ private int computeDepthFromRoot(Long nodeId, Map<Long, ProductionBomStructure> structureById, Map<Long, Integer> depthMap) {
+ if (depthMap.containsKey(nodeId)) {
+ return depthMap.get(nodeId);
+ }
+
+ ProductionBomStructure structure = structureById.get(nodeId);
+ if (structure == null) {
+ depthMap.put(nodeId, 1);
+ return 1;
+ }
+
+ Long parentId = structure.getParentId();
+ if (parentId == null || parentId == 0L) {
+ // 鏍硅妭鐐规繁搴︿负1
+ depthMap.put(nodeId, 1);
+ return 1;
+ }
+
+ // 瀛愯妭鐐规繁搴� = 鐖惰妭鐐规繁搴� + 1
+ int parentDepth = computeDepthFromRoot(parentId, structureById, depthMap);
+ int depth = parentDepth + 1;
+ depthMap.put(nodeId, depth);
+ return depth;
+ }
+
+ private void buildOperationListPostOrder(Long parentId,
+ Map<Long, List<ProductionBomStructure>> treeMap,
+ Map<String, ProductionBomStructure> uniqueOperationMap,
+ Map<Long, ProductionBomStructure> structureById,
+ Long rootProductModelId) {
+ List<ProductionBomStructure> children = treeMap.get(parentId);
+ if (children == null || children.isEmpty()) {
+ return;
+ }
+ for (ProductionBomStructure child : children) {
+ // 鍏堥�掑綊澶勭悊瀛愯妭鐐�
+ buildOperationListPostOrder(child.getId(), treeMap, uniqueOperationMap, structureById, rootProductModelId);
+
+ // 鍐嶅鐞嗗綋鍓嶈妭鐐�
+ if (child.getTechnologyOperationId() != null) {
+ Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
+ String key = buildBomOperationDedupKey(child, outputProductModelId);
+ // 鍘婚噸鏃朵繚鐣欐繁搴︽渶澶х殑鎿嶄綔锛堝悗搴忛亶鍘嗗厛閬囧埌娣卞眰鑺傜偣锛屾墍浠ョ洿鎺ヨ鐩栧嵆鍙級
+ uniqueOperationMap.put(key, child);
+ }
+ }
}
private Map<String, Deque<ProductionOrderRoutingOperation>> buildExistingRoutingOperationBucketMap(List<ProductionOrderRoutingOperation> existingOperationList) {
@@ -568,7 +770,7 @@
return;
}
if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) {
- throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収");
+ throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収" + task.getWorkOrderNo());
}
long reportCount = productionProductMainMapper.selectCount(
Wrappers.<ProductionProductMain>lambdaQuery()
--
Gitblit v1.9.3