| doc/20261020_工序是否领料与生产BOM结构领料标记.sql | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/production/pojo/ProductionBomStructure.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/ruoyi/technology/pojo/TechnologyOperation.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/resources/mapper/production/ProductionBomStructureMapper.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/resources/mapper/technology/TechnologyOperationMapper.xml | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
doc/20261020_¹¤ÐòÊÇ·ñÁìÁÏÓëÉú²úBOM½á¹¹ÁìÁϱê¼Ç.sql
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,112 @@ -- ============================================================================ -- å·¥åºå¢å âæ¯å¦é¢æâæ è®°ï¼å¹¶åæ¥å°ç产BOMç»æï¼ç产订å颿å°è´¦ä½¿ç¨ï¼ -- -- èæ¯ï¼ -- ç产订åç颿å°è´¦åæ¥æ BOM çå¶åèç¹åæ¨éè¦é¢æçç©æï¼BOM å±çº§ä¸å¤ï¼ -- é¢æç»æåå®é æ åµå¯¹ä¸ä¸ï¼BOM éä¸å¤§å ç©æéè¦é¢æï¼ç®åºæ¥åªå©å æ¡ï¼ã -- ç°æ¹ä¸ºç±å·¥åºä¸çâæ¯å¦é¢æâæ è®°å³å®é¢æèå´ï¼ -- 1) å·¥åºè¡¨ technology_operation å¢å is_pickï¼å·¥åºç®¡ç-æ°å¢/ç¼è¾å·¥åº å¾éâæ¯å¦é¢æâï¼ï¼ -- 2) ç产计åä¸åï¼çæç产订åå¿«ç §ï¼æ¶ï¼æå·¥åºç is_pick å¸¦å° production_bom_structureï¼ -- 3) ç产订å-颿å°è´¦æ is_pick = 1 çå·¥åºç©æåæ°ï¼è¯»åæ¶ä¼ç¨å·¥åºä¸»æ°æ®çææ°æ è®°å·æ°å¿«ç §å¼ï¼ -- å æ¤å·¥åºä¸è°æ´âæ¯å¦é¢æâåæ ééæ°ä¸å计åå³å¯çæï¼ -- production_bom_structure.is_pick 主è¦ç¨äºå¿«ç §ççãæ¥è¡¨åå·¥åºè¢«å é¤åçå åºã -- -- æ§è¡è¯´æï¼ -- 1. èæ¬å¯é夿§è¡ï¼åå·²å卿¶ä¼èªå¨è·³è¿ï¼ -- 2. å»ºè®®å æ§è¡æ¬èæ¬ï¼åå级ç¨åºï¼æåå¨å·¥åºç®¡çéå¾ééè¦é¢æçå·¥åºï¼ -- 3. 第 3 æ¥åå¡«ä» ç¨äºæåé订åBOMå¿«ç §éç is_pick å·æå·¥åºææ°æ è®°ï¼æ¥è¡¨/追溯å£å¾ï¼ï¼ -- ä¸å½±å颿å°è´¦ç宿¶åæ°ã -- ============================================================================ -- ---------------------------------------------------------------------------- -- 1. å·¥åºè¡¨ï¼å¢å âæ¯å¦é¢æâåæ®µ -- ---------------------------------------------------------------------------- SET @col_exists = ( SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'technology_operation' AND COLUMN_NAME = 'is_pick' ); SET @ddl = IF(@col_exists = 0, 'ALTER TABLE technology_operation ADD COLUMN is_pick TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''æ¯å¦é¢æï¼0å¦ï¼1æ¯'' AFTER is_production', 'SELECT ''technology_operation.is_pick å·²åå¨ï¼è·³è¿'' AS msg'); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- ---------------------------------------------------------------------------- -- 2. ç产订åBOMç»æè¡¨ï¼å¢å âæ¯å¦é¢æâåæ®µï¼å¿«ç §æ¥èªå·¥åºï¼ -- ---------------------------------------------------------------------------- SET @col_exists = ( SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'production_bom_structure' AND COLUMN_NAME = 'is_pick' ); SET @ddl = IF(@col_exists = 0, 'ALTER TABLE production_bom_structure ADD COLUMN is_pick TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''æ¯å¦é¢æï¼æ¥èªå·¥åºï¼0å¦ï¼1æ¯'' AFTER technology_operation_id', 'SELECT ''production_bom_structure.is_pick å·²åå¨ï¼è·³è¿'' AS msg'); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- ---------------------------------------------------------------------------- -- 3. åéç产BOMç»æåå¡«ï¼æå·¥åºå½åçâæ¯å¦é¢æâæ è®°åæ¥å¿«ç §å¼ -- 馿¬¡æ§è¡ï¼å·¥åºè¿æ²¡å¼å§æ è®°ï¼æ¶ä¸ä¼æ¹å任使°æ®ï¼ -- åç»å¨å·¥åºç®¡çéå¾é/åæ¶âæ¯å¦é¢æâåï¼å¯å次æ§è¡æ¬è¯å¥ï¼ -- 让已ç»ä¸åç订åBOMå¿«ç §åæ¥ææ°æ è®°ï¼ç¨äºæ¥è¡¨/追溯ï¼é¢æå°è´¦è¯»åæ¶æ¬èº«ä¹ä¼åå·¥åºææ°æ è®°ï¼ã -- ---------------------------------------------------------------------------- UPDATE production_bom_structure pbs INNER JOIN technology_operation top1 ON top1.id = pbs.technology_operation_id SET pbs.is_pick = IFNULL(top1.is_pick, 0) WHERE IFNULL(pbs.is_pick, 0) <> IFNULL(top1.is_pick, 0); -- å¯éï¼æé£é©ï¼é»è®¤ä¸æ§è¡ï¼ï¼æåéå·¥åºå ¨é¨æ 记为éè¦é¢æã -- 注æï¼æ§è¡åï¼ææåå²è®¢åç颿å°è´¦é½ä¼åæâæå ¨é¨å·¥åºé¢æâï¼è¯·ç¡®è®¤å£å¾ååæ¾å¼ã -- UPDATE technology_operation SET is_pick = 1 WHERE is_pick = 0; -- ---------------------------------------------------------------------------- -- 4. æ ¡éªSQLï¼æéæ§è¡ï¼ä¸å½±åæ°æ®ï¼ -- ---------------------------------------------------------------------------- -- 4.1 æ¥çåªäºå·¥åºå¨BOMç»æä¸è¢«ä½¿ç¨ï¼å¸®å©å³å®ç»åªäºå·¥åºå¼å¯âæ¯å¦é¢æâ -- SELECT top1.id, -- top1.no, -- top1.name, -- top1.is_pick, -- COUNT(pbs.id) AS bom_row_count -- FROM technology_operation top1 -- LEFT JOIN production_bom_structure pbs ON pbs.technology_operation_id = top1.id -- GROUP BY top1.id, top1.no, top1.name, top1.is_pick -- ORDER BY bom_row_count DESC; -- 4.2 æ¥çæä¸ªç产订åçBOMç»æé¢ææ è®°ï¼æ :productionOrderId æ¢æå®é 订åIDï¼ -- SELECT pbs.id, -- pbs.parent_id, -- pbs.technology_operation_id, -- top1.name AS operation_name, -- pbs.product_model_id, -- pm.model, -- pbs.unit_quantity, -- pbs.demanded_quantity, -- pbs.is_pick -- FROM production_bom_structure pbs -- LEFT JOIN technology_operation top1 ON top1.id = pbs.technology_operation_id -- LEFT JOIN product_model pm ON pm.id = pbs.product_model_id -- WHERE pbs.production_order_id = :productionOrderId -- ORDER BY pbs.id; -- ---------------------------------------------------------------------------- -- 5. åæ»ï¼å¦éï¼ï¼ -- ALTER TABLE production_bom_structure DROP COLUMN is_pick; -- ALTER TABLE technology_operation DROP COLUMN is_pick; -- ---------------------------------------------------------------------------- src/main/java/com/ruoyi/production/pojo/ProductionBomStructure.java
@@ -40,6 +40,9 @@ @Schema(description = "å·¥åºid") private Long technologyOperationId; @Schema(description = "æ¯å¦é¢æ æ¥æºå·¥åºçâæ¯å¦é¢æâæ è®°ï¼é¢æå°è´¦åªé¢åæ è®°äºé¢æçå·¥åºç©æ") private Boolean isPick; @Schema(description = "ç产订åBOMid") private Long productionOrderBomId; src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -131,10 +131,15 @@ List<ProductionBomStructure> updateList = new ArrayList<>(); Map<String, ProductionBomStructure> tempEntityMap = new HashMap<>(); Map<Long, Boolean> operationPickMap = loadOperationPickMap(flatDtoList.stream() .map(ProductionBomStructureDto::getTechnologyOperationId) .collect(Collectors.toList())); for (ProductionBomStructureDto item : flatDtoList) { ProductionBomStructure entity = new ProductionBomStructure(); BeanUtils.copyProperties(item, entity); entity.setProductionOrderBomId(orderBomId); entity.setIsPick(operationPickMap.getOrDefault(item.getTechnologyOperationId(), Boolean.FALSE)); if (item.getId() == null) { entity.setParentId(null); insertList.add(entity); @@ -853,6 +858,26 @@ return technologyOperationMapper.selectById(technologyOperationId); } /** * æ¹é读åå·¥åºçâæ¯å¦é¢æâæ è®°ï¼ä¿è¯ç产BOMç»æä¸ç颿æ è®°ä¸å·¥åºä¸»æ°æ®ä¸è´ã */ private Map<Long, Boolean> loadOperationPickMap(List<Long> technologyOperationIds) { if (technologyOperationIds == null || technologyOperationIds.isEmpty()) { return Collections.emptyMap(); } Set<Long> operationIdSet = technologyOperationIds.stream() .filter(Objects::nonNull) .collect(Collectors.toSet()); if (operationIdSet.isEmpty()) { return Collections.emptyMap(); } return technologyOperationMapper.selectBatchIds(operationIdSet).stream() .filter(item -> item != null && item.getId() != null) .collect(Collectors.toMap(TechnologyOperation::getId, item -> Boolean.TRUE.equals(item.getIsPick()), (left, right) -> left)); } private String generateNextTaskNo() { String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); ProductionOperationTask latestTask = productionOperationTaskMapper.selectOne( src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -371,6 +371,9 @@ productionOrderBomMapper.insert(orderBom); Map<Long, Long> idMap = new HashMap<>(); Map<Long, Boolean> operationPickMap = loadOperationPickMap(structureList.stream() .map(TechnologyBomStructure::getOperationId) .collect(Collectors.toList())); for (TechnologyBomStructure source : structureList) { // åèç¹ parentId éè¦æ å°ææ°å¿«ç §èç¹ idï¼æè½ä¿çåå§ BOM å±çº§ã ProductionBomStructure target = new ProductionBomStructure(); @@ -379,6 +382,7 @@ target.setParentId(source.getParentId() == null ? null : idMap.get(source.getParentId())); target.setProductModelId(source.getProductModelId()); target.setTechnologyOperationId(source.getOperationId()); target.setIsPick(operationPickMap.getOrDefault(source.getOperationId(), Boolean.FALSE)); target.setUnitQuantity(source.getUnitQuantity()); target.setDemandedQuantity(defaultDecimal(orderQuantity) .multiply(defaultDecimal(source.getUnitQuantity()))); @@ -387,6 +391,26 @@ idMap.put(source.getId(), target.getId()); } return orderBom; } /** * æ¹é读åå·¥åºçâæ¯å¦é¢æâæ è®°ï¼é¿å BOMå¿«ç §éè¡æ¥è¯¢å·¥åºè¡¨ã */ private Map<Long, Boolean> loadOperationPickMap(List<Long> technologyOperationIds) { if (technologyOperationIds == null || technologyOperationIds.isEmpty()) { return Collections.emptyMap(); } Set<Long> operationIdSet = technologyOperationIds.stream() .filter(Objects::nonNull) .collect(Collectors.toSet()); if (operationIdSet.isEmpty()) { return Collections.emptyMap(); } return technologyOperationMapper.selectBatchIds(operationIdSet).stream() .filter(item -> item != null && item.getId() != null) .collect(Collectors.toMap(TechnologyOperation::getId, item -> Boolean.TRUE.equals(item.getIsPick()), (left, right) -> left)); } private void clearProductionSnapshot(Long productionOrderId) { @@ -1076,32 +1100,62 @@ } } // æ¶é订åæåè§æ ¼IDï¼å å«ç产订åæåè§æ ¼ä¸BOMæ ¹èç¹è§æ ¼ï¼ç¨äºæé¤âèªå·±âè¿ä¸ç©æ // production_bom_structure.is_pick æ¯ç产计åä¸åæ¶çå·¥åºé¢ææ è®°å¿«ç §ï¼ // 颿å°è´¦è¯»åæ¶ä»¥å·¥åºä¸»æ°æ®çææ°æ 记为åï¼ä¿è¯å·¥åºä¸çâæ¯å¦é¢æâè°æ´åæ ééæ°ä¸åå³å¯çæï¼ // å·¥åºå·²è¢«å 餿¶ä¿çå¿«ç §å¼ï¼é¿å åå²è®¢åç颿èå´ä¸¢å¤±ã Map<Long, Boolean> operationPickMap = loadOperationPickMap(bomStructureList.stream() .filter(Objects::nonNull) .map(ProductionBomStructureVo::getTechnologyOperationId) .collect(Collectors.toList())); for (ProductionBomStructureVo structure : bomStructureList) { if (structure == null || structure.getTechnologyOperationId() == null) { continue; } Boolean latestPick = operationPickMap.get(structure.getTechnologyOperationId()); if (latestPick != null) { structure.setIsPick(latestPick); } } // æ¶é订åæåè§æ ¼IDï¼ç产订åæåè§æ ¼ + 订åBOMå¿«ç §çæ ¹èç¹è§æ ¼ï¼ç¨äºæé¤âèªå·±âè¿ä¸ç©æã // 注æï¼BOMç»æéé¢æç©ææ¬èº«ä¹å¯è½æ¯ parent_id 为空çç¬ç«èç¹ï¼è¿éä¸è½åææææ ¹èç¹é½å½ææåæé¤ï¼ // å¦åâ颿âå·¥åºä¸çç©æä¼è¢«æ´ä½è¿æ»¤æã Set<Long> finishedProductModelIds = new HashSet<>(); if (productionOrder != null && productionOrder.getProductModelId() != null) { finishedProductModelIds.add(productionOrder.getProductModelId()); } bomStructureList.stream() .filter(s -> s != null && (s.getParentId() == null || s.getParentId() == 0)) .map(ProductionBomStructureVo::getProductModelId) .filter(Objects::nonNull) .forEach(finishedProductModelIds::add); if (orderBom.getProductModelId() != null) { finishedProductModelIds.add(orderBom.getProductModelId()); } // æ¶éææè¢«å¼ç¨ä¸ºç¶çº§çèç¹IDï¼BOM仿åä¸éå·¥åºå¾éé ç½®åä¸éå·¥åºï¼ // ä¸é´èç¹æ¯ä¸ä¸éå·¥åºç产åºï¼èªå¶ï¼ï¼åªææ¯æ¡åæ¯æéå±çå¶åèç¹ææ¯çæ£éè¦é¢ç¨çç©æã // ä¸é´èç¹æ¯ä¸ä¸éå·¥åºç产åºï¼èªå¶ï¼ï¼æ§å£å¾åªææ¯æ¡åæ¯æéå±çå¶åèç¹ææ¯çæ£éè¦é¢ç¨çç©æã Set<Long> parentNodeIds = bomStructureList.stream() .filter(s -> s != null && s.getParentId() != null && s.getParentId() != 0) .map(ProductionBomStructureVo::getParentId) .filter(Objects::nonNull) .collect(Collectors.toSet()); // è¿æ»¤åºå¶åèç¹ï¼å®é 颿项ï¼ï¼éæ ¹èç¹ãéä¸é´èç¹ï¼å¹¶æé¤ä¸è®¢åæååè§æ ¼çç©æï¼èªå¶æåæ éé¢æï¼ List<ProductionBomStructureVo> childStructureList = bomStructureList.stream() .filter(s -> s != null && s.getParentId() != null && s.getParentId() != 0) .filter(s -> s.getId() == null || !parentNodeIds.contains(s.getId())) // 颿èå´ä»¥å·¥åºçâæ¯å¦é¢æâæ 记为åï¼åªææ è®°äºé¢æçå·¥åºï¼å ¶æ¶èçç©ææè¿å ¥é¢æå°è´¦ã // 注æï¼é¢æç©æå¨BOMç»æä¸å¯è½æ¯ç¬ç«èç¹ï¼parent_id 为空ï¼ï¼æä»¥è¿éä¸éå¶å±çº§ï¼åªçå·¥åºæ è®°ï¼ // åªæé¤ä¸è®¢åæååè§æ ¼çç©æï¼æåæ¬èº«æ é颿ï¼ã List<ProductionBomStructureVo> markedPickStructureList = bomStructureList.stream() .filter(s -> s != null && Boolean.TRUE.equals(s.getIsPick())) .filter(s -> s.getProductModelId() == null || !finishedProductModelIds.contains(s.getProductModelId())) .collect(Collectors.toList()); // å®é 颿项ï¼ä¼å 使ç¨å·¥åºé¢ææ è®°ï¼ // å ¼å®¹å岿°æ®ï¼å½è¯¥è®¢åBOMç»æéæ²¡æä»»ä½å·¥åºæ è®°é¢ææ¶ï¼åéä¸ºåæ¥çâå¶åèç¹é¢æâè§åï¼ // é¿å å°æªå¯ç¨âæ¯å¦é¢æâæ è®°çå®¢æ·æå¼é¢æå°è´¦æ¶æ°æ®çªç¶ä¸ºç©ºã List<ProductionBomStructureVo> childStructureList = markedPickStructureList; if (childStructureList.isEmpty()) { childStructureList = bomStructureList.stream() .filter(s -> s != null && s.getParentId() != null && s.getParentId() != 0) .filter(s -> s.getId() == null || !parentNodeIds.contains(s.getId())) .filter(s -> s.getProductModelId() == null || !finishedProductModelIds.contains(s.getProductModelId())) .collect(Collectors.toList()); } // éåå¤çæ°æ®å¹¶ç»è£ ç»æ List<Long> productModelIds = childStructureList.stream() .map(ProductionBomStructureVo::getProductModelId) src/main/java/com/ruoyi/technology/pojo/TechnologyOperation.java
@@ -65,4 +65,7 @@ @Schema(description = "æ¯å¦ç产") private Boolean isProduction; @Schema(description = "æ¯å¦é¢æ æ è®°è¯¥å·¥åºæ¯å¦éè¦é¢æ") private Boolean isPick; } src/main/resources/mapper/production/ProductionBomStructureMapper.xml
@@ -9,6 +9,7 @@ <result column="production_order_id" property="productionOrderId" /> <result column="product_model_id" property="productModelId" /> <result column="technology_operation_id" property="technologyOperationId" /> <result column="is_pick" property="isPick" /> <result column="production_order_bom_id" property="productionOrderBomId" /> <result column="unit_quantity" property="unitQuantity" /> <result column="demanded_quantity" property="demandedQuantity" /> src/main/resources/mapper/technology/TechnologyOperationMapper.xml
@@ -12,6 +12,8 @@ <result column="remark" property="remark" /> <result column="salary_quota" property="salaryQuota" /> <result column="is_quality" property="isQuality" /> <result column="is_production" property="isProduction" /> <result column="is_pick" property="isPick" /> <result column="type" property="type" /> <result column="device_ledger_id" property="deviceLedgerId" /> <result column="create_user" property="createUser" />