From de4ca61aa27d7f284a03aebd801bcc3d6a75bc6a Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期四, 21 五月 2026 15:03:35 +0800
Subject: [PATCH] 修改生产订单中的工艺路线项目是否生产后,更新生产工单数据
---
src/main/resources/mapper/production/ProductionOperationTaskMapper.xml | 3
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java | 2
src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java | 3
src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java | 3
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java | 149 +++++++++++++++++++++++++++--
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java | 2
src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java | 137 +++++++++++++++++++++++++++
7 files changed, 283 insertions(+), 16 deletions(-)
diff --git a/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java b/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
index 965cbf3..8a75dcd 100644
--- a/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
+++ b/src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
@@ -44,4 +44,7 @@
@Schema(description = "缁撴潫鏃ユ湡")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate endDate;
+
+ @Schema(description = "鏄惁鐢熶骇")
+ private Integer isProduction;
}
diff --git a/src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java b/src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java
index dda1aa0..2765c10 100644
--- a/src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java
+++ b/src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java
@@ -39,7 +39,7 @@
@PostMapping("/updateRouteItem")
@Operation(summary = "淇敼鐢熶骇璁㈠崟鐨勫伐鑹鸿矾绾胯鎯�")
public R updateRouteItem(@RequestBody ProductionOrderRoutingOperation productionOrderRoutingOperation) {
- return R.ok(productionOrderRoutingOperationService.updateById(productionOrderRoutingOperation));
+ return R.ok(productionOrderRoutingOperationService.updateRouteItem(productionOrderRoutingOperation));
}
@DeleteMapping("/deleteRouteItem/{id}")
diff --git a/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java b/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
index 2377dc3..8878006 100644
--- a/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
+++ b/src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
@@ -8,6 +8,8 @@
R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
+ R updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
+
R deleteRouteItem(Long id);
int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
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 200e95f..40dd74c 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;
@@ -262,7 +263,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;
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
index 3d16a07..75d0696 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
@@ -4,21 +4,15 @@
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.framework.web.domain.R;
-import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
-import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
-import com.ruoyi.production.mapper.ProductionOrderRoutingOperationParamMapper;
-import com.ruoyi.production.mapper.ProductionProductMainMapper;
-import com.ruoyi.production.pojo.ProductionOperationTask;
-import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
-import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
-import com.ruoyi.production.pojo.ProductionProductMain;
+import com.ruoyi.production.mapper.*;
+import com.ruoyi.production.util.TaskPlanQuantityUtil;
+import com.ruoyi.technology.mapper.*;
+import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductionOrderRoutingOperationService;
import com.ruoyi.production.service.ProductionProductMainService;
-import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
-import com.ruoyi.technology.mapper.TechnologyParamMapper;
-import com.ruoyi.technology.pojo.TechnologyOperationParam;
-import com.ruoyi.technology.pojo.TechnologyParam;
+import com.ruoyi.technology.pojo.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -26,8 +20,7 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
@Service
@Transactional(rollbackFor = Exception.class)
@@ -42,6 +35,11 @@
private final TechnologyOperationParamMapper technologyOperationParamMapper;
private final TechnologyParamMapper technologyParamMapper;
private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
+ private final ProductionOrderMapper productionOrderMapper;
+ private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
+ private final ProductionOrderBomMapper productionOrderBomMapper;
+ private final ProductionBomStructureMapper productionBomStructureMapper;
+ private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
@Override
public R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
@@ -102,6 +100,109 @@
productionOperationTaskMapper.insert(productionOperationTask);
}
return R.ok();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public R updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
+ Long operationId = productionOrderRoutingOperation.getId();
+
+ // 鏇存柊宸ヨ壓璺嚎宸ュ簭
+ productionOrderRoutingOperationMapper.updateById(productionOrderRoutingOperation);
+
+ // 閲嶆柊鏌ヨ瀹屾暣璁板綍锛堝墠绔彲鑳芥病鏈変紶閫掓墍鏈夊瓧娈碉紝濡� productionOrderId锛�
+ ProductionOrderRoutingOperation updatedOperation = productionOrderRoutingOperationMapper.selectById(operationId);
+ if (updatedOperation == null) {
+ throw new ServiceException("宸ヨ壓璺嚎宸ュ簭涓嶅瓨鍦�");
+ }
+
+ // 鏌ヨ鏄惁瀛樺湪宸ュ崟
+ ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectOne(
+ new LambdaQueryWrapper<ProductionOperationTask>()
+ .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, operationId)
+ .last("limit 1"));
+
+ // 鏍规嵁鏄惁闇�瑕佺敓浜ц繘琛屽鐞�
+ Boolean isProduction = updatedOperation.getIsProduction();
+
+ if (Boolean.TRUE.equals(isProduction)) {
+ // 闇�瑕佺敓浜э細妫�鏌ュ伐鍗曟槸鍚﹀瓨鍦紝涓嶅瓨鍦ㄥ垯鐢熸垚
+ if (productionOperationTask == null) {
+ ProductionOperationTask task = new ProductionOperationTask();
+ task.setProductionOrderRoutingOperationId(updatedOperation.getId());
+ task.setProductionOrderId(updatedOperation.getProductionOrderId());
+ // 鑾峰彇鐢熶骇璁㈠崟
+ ProductionOrder productionOrder = productionOrderMapper.selectById(updatedOperation.getProductionOrderId());
+ if (productionOrder == null) {
+ throw new ServiceException("鐢熶骇璁㈠崟涓嶅瓨鍦�");
+ }
+
+ // 鑾峰彇璁㈠崟BOM
+ ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
+ Wrappers.<ProductionOrderBom>lambdaQuery()
+ .eq(ProductionOrderBom::getProductionOrderId, productionOrder.getId()));
+
+ // 纭畾鏍逛骇鍝佽鏍糏D
+ Long rootProductModelId = orderBom != null && orderBom.getProductModelId() != null
+ ? orderBom.getProductModelId()
+ : productionOrder.getProductModelId();
+
+ // 鑾峰彇BOM缁撴瀯鍒楄〃
+ List<ProductionBomStructure> orderBomStructureList = orderBom == null || orderBom.getId() == null
+ ? Collections.emptyList()
+ : productionBomStructureMapper.selectList(
+ Wrappers.<ProductionBomStructure>lambdaQuery()
+ .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
+ .orderByAsc(ProductionBomStructure::getId));
+
+ // 鏋勫缓宸ュ簭闇�姹傞噺鏄犲皠
+ Map<String, BigDecimal> operationDemandedQuantityMap =
+ TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(orderBomStructureList, rootProductModelId);
+
+ // 鑾峰彇宸ヨ壓璺嚎宸ュ簭锛堢敤浜庤绠楄鍒掓暟閲忥級
+ TechnologyRoutingOperation sourceOperation = technologyRoutingOperationMapper.selectById(
+ updatedOperation.getTechnologyRoutingOperationId());
+ // 灏嗗師鏉ョ殑绉佹湁鏂规硶鏇挎崲涓鸿皟鐢ㄥ伐鍏风被
+ BigDecimal planQuantity = TaskPlanQuantityUtil.resolveTaskPlanQuantity(
+ sourceOperation,
+ operationDemandedQuantityMap,
+ productionOrder,
+ rootProductModelId);
+ task.setPlanQuantity(planQuantity);
+ task.setCompleteQuantity(BigDecimal.ZERO);
+ task.setWorkOrderNo(generateNextTaskNo());
+ task.setStatus(2);
+ productionOperationTaskMapper.insert(task);
+ }
+ } else {
+ // 涓嶉渶瑕佺敓浜э細妫�鏌ュ伐鍗曟槸鍚﹀瓨鍦�
+ if (productionOperationTask != null) {
+ validateTaskCanRemove(productionOperationTask);
+ // 娌℃湁鎶ュ伐锛屽垯鍒犻櫎宸ュ崟
+ productionOperationTaskMapper.deleteById(productionOperationTask.getId());
+ }
+ }
+
+ return R.ok();
+ }
+
+ private void validateTaskCanRemove(ProductionOperationTask task) {
+ if (task == null || task.getId() == null) {
+ return;
+ }
+ if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) {
+ throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ簭蹇収");
+ }
+ long reportCount = productionProductMainMapper.selectCount(
+ Wrappers.<ProductionProductMain>lambdaQuery()
+ .eq(ProductionProductMain::getProductionOperationTaskId, task.getId()));
+ if (reportCount > 0) {
+ throw new ServiceException("宸ュ簭宸蹭骇鐢熸姤宸ヨ褰曪紝鏃犳硶鏍规嵁 BOM 鍙樻洿鍒犻櫎瀵瑰簲宸ュ崟");
+ }
+ }
+
+ private BigDecimal defaultDecimal(BigDecimal value) {
+ return value == null ? BigDecimal.ZERO : value;
}
@Override
@@ -182,4 +283,24 @@
}
return 0;
}
+
+ private String generateNextTaskNo() {
+ // 鐢熸垚涓嬩竴涓敓浜у伐鍗曞彿
+ String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+ String prefix = "GD" + datePrefix;
+ ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne(
+ Wrappers.<ProductionOperationTask>lambdaQuery()
+ .likeRight(ProductionOperationTask::getWorkOrderNo, prefix)
+ .orderByDesc(ProductionOperationTask::getWorkOrderNo)
+ .last("limit 1"));
+ int sequence = 1;
+ if (lastTask != null && lastTask.getWorkOrderNo() != null && lastTask.getWorkOrderNo().startsWith(prefix)) {
+ try {
+ sequence = Integer.parseInt(lastTask.getWorkOrderNo().substring(prefix.length())) + 1;
+ } catch (NumberFormatException ignored) {
+ sequence = 1;
+ }
+ }
+ return prefix + String.format("%03d", sequence);
+ }
}
diff --git a/src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java b/src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java
new file mode 100644
index 0000000..e82d7e4
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/util/TaskPlanQuantityUtil.java
@@ -0,0 +1,137 @@
+package com.ruoyi.production.util;
+
+import com.ruoyi.production.pojo.ProductionBomStructure;
+import com.ruoyi.production.pojo.ProductionOrder;
+import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
+import com.ruoyi.technology.pojo.TechnologyRoutingOperation;
+import lombok.experimental.UtilityClass;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 宸ュ崟璁″垝鏁伴噺璁$畻宸ュ叿绫�
+ */
+@UtilityClass
+public class TaskPlanQuantityUtil {
+
+ /**
+ * 璁$畻宸ュ崟璁″垝鏁伴噺锛堜娇鐢� TechnologyRoutingOperation锛�
+ */
+ public BigDecimal resolveTaskPlanQuantity(TechnologyRoutingOperation sourceOperation,
+ Map<String, BigDecimal> operationDemandedQuantityMap,
+ ProductionOrder productionOrder,
+ Long rootProductModelId) {
+ if (sourceOperation == null || operationDemandedQuantityMap == null || operationDemandedQuantityMap.isEmpty()) {
+ return defaultDecimal(productionOrder == null ? null : productionOrder.getQuantity());
+ }
+ Long outputProductModelId = sourceOperation.getProductModelId() != null
+ ? sourceOperation.getProductModelId()
+ : rootProductModelId;
+ String key = buildOperationDemandedQuantityKey(sourceOperation.getTechnologyOperationId(), outputProductModelId);
+ BigDecimal planQuantity = operationDemandedQuantityMap.get(key);
+ return planQuantity != null ? planQuantity : defaultDecimal(productionOrder == null ? null : productionOrder.getQuantity());
+ }
+
+ /**
+ * 璁$畻宸ュ崟璁″垝鏁伴噺锛堜娇鐢� ProductionOrderRoutingOperation锛�
+ */
+ public BigDecimal resolveTaskPlanQuantity(ProductionOrderRoutingOperation routingOperation,
+ Map<String, BigDecimal> demandedQuantityMap,
+ BigDecimal orderQuantity,
+ Long rootProductModelId) {
+ if (routingOperation == null || demandedQuantityMap == null || demandedQuantityMap.isEmpty()) {
+ return orderQuantity;
+ }
+ Long outputProductModelId = routingOperation.getProductModelId() != null
+ ? routingOperation.getProductModelId()
+ : rootProductModelId;
+ String key = buildOperationDemandedQuantityKey(routingOperation.getTechnologyOperationId(), outputProductModelId);
+ BigDecimal planQuantity = demandedQuantityMap.get(key);
+ return planQuantity != null ? planQuantity : orderQuantity;
+ }
+
+ /**
+ * 鏋勫缓宸ュ簭闇�姹傞噺鏄犲皠琛�
+ */
+ public Map<String, BigDecimal> buildOperationDemandedQuantityMap(List<ProductionBomStructure> bomStructures, Long rootProductModelId) {
+ if (bomStructures == null || bomStructures.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map<Long, ProductionBomStructure> structureById = new HashMap<>();
+ for (ProductionBomStructure item : bomStructures) {
+ if (item != null && item.getId() != null) {
+ structureById.put(item.getId(), item);
+ }
+ }
+ Map<String, BigDecimal> demandedQuantityMap = new HashMap<>();
+ Set<String> mergedOutputNodeKeySet = new HashSet<>();
+ for (ProductionBomStructure bomStructure : bomStructures) {
+ if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) {
+ continue;
+ }
+ ProductionBomStructure outputNode = resolveOperationOutputNode(bomStructure, structureById);
+ Long outputProductModelId = resolveOutputProductModelId(outputNode, rootProductModelId);
+ if (outputProductModelId == null) {
+ continue;
+ }
+ String mergedOutputNodeKey = buildOperationOutputNodeKey(bomStructure.getTechnologyOperationId(),
+ outputNode == null ? null : outputNode.getId(), outputProductModelId);
+ if (!mergedOutputNodeKeySet.add(mergedOutputNodeKey)) {
+ continue;
+ }
+ BigDecimal demandedQuantity = defaultDecimal(outputNode == null ? null : outputNode.getDemandedQuantity());
+ String key = buildOperationDemandedQuantityKey(bomStructure.getTechnologyOperationId(), outputProductModelId);
+ demandedQuantityMap.merge(key, demandedQuantity, BigDecimal::add);
+ }
+ return demandedQuantityMap;
+ }
+
+ /**
+ * 鏋勫缓宸ュ簭闇�姹傞噺key
+ */
+ public String buildOperationDemandedQuantityKey(Long operationId, Long outputProductModelId) {
+ return String.valueOf(operationId) + "#" + String.valueOf(outputProductModelId);
+ }
+
+ /**
+ * 鏋勫缓杈撳嚭鑺傜偣key
+ */
+ public String buildOperationOutputNodeKey(Long operationId, Long outputNodeId, Long outputProductModelId) {
+ return String.valueOf(operationId) + "#" + String.valueOf(outputNodeId) + "#" + String.valueOf(outputProductModelId);
+ }
+
+ /**
+ * 瑙f瀽宸ュ簭杈撳嚭鑺傜偣
+ */
+ public ProductionBomStructure resolveOperationOutputNode(ProductionBomStructure bomStructure,
+ Map<Long, ProductionBomStructure> structureById) {
+ if (bomStructure == null) {
+ return null;
+ }
+ if (bomStructure.getParentId() == null) {
+ return bomStructure;
+ }
+ ProductionBomStructure parent = structureById.get(bomStructure.getParentId());
+ return parent != null ? parent : bomStructure;
+ }
+
+ /**
+ * 瑙f瀽杈撳嚭浜у搧瑙勬牸ID
+ */
+ public Long resolveOutputProductModelId(ProductionBomStructure outputNode, Long rootProductModelId) {
+ if (outputNode == null) {
+ return rootProductModelId;
+ }
+ return outputNode.getProductModelId() != null ? outputNode.getProductModelId() : rootProductModelId;
+ }
+
+ /**
+ * 榛樿BigDecimal鍊�
+ */
+ public BigDecimal defaultDecimal(BigDecimal value) {
+ return value == null ? BigDecimal.ZERO : value;
+ }
+
+}
diff --git a/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml b/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
index f029ef7..199eb21 100644
--- a/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
+++ b/src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
@@ -64,6 +64,9 @@
<if test="c != null and c.status != null">
and pot.status = #{c.status}
</if>
+ <if test="c != null and c.isProduction != null">
+ and poro.is_production = #{c.isProduction}
+ </if>
<if test="c != null and c.workOrderNo != null and c.workOrderNo != ''">
and pot.work_order_no like concat('%', #{c.workOrderNo}, '%')
</if>
--
Gitblit v1.9.3