From e09f103259fa602382bb5ce2a03361a6397af46a Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 15 十月 2026 11:49:15 +0800
Subject: [PATCH] feat(mes): 优化MES模块生产调度与数据管理功能

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/card/MesProCardServiceImpl.java |   95 ++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 89 insertions(+), 6 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/card/MesProCardServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/card/MesProCardServiceImpl.java
index 86eb479..43f415d 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/card/MesProCardServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/card/MesProCardServiceImpl.java
@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.mes.service.pro.card;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -7,11 +8,14 @@
 import cn.iocoder.yudao.module.mes.controller.admin.pro.card.vo.MesProCardPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.pro.card.vo.MesProCardSaveReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.card.MesProCardDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.card.MesProCardProcessDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderProcessDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.pro.card.MesProCardMapper;
 import cn.iocoder.yudao.module.mes.enums.pro.MesProWorkOrderStatusEnum;
 import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
 import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
+import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderProcessService;
 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
 import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService;
 import jakarta.annotation.Resource;
@@ -20,13 +24,19 @@
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
 /**
  * MES 鐢熶骇娴佽浆鍗� Service 瀹炵幇绫�
  *
- * @author 鑺嬮亾婧愮爜
+ * @author 瓒呯骇绠$悊鍛�
  */
 @Service
 @Validated
@@ -44,33 +54,46 @@
     private MesMdItemService itemService;
     @Resource
     private MesWmBarcodeService barcodeService;
+    @Resource
+    private MesProWorkOrderProcessService workOrderProcessService;
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Long createCard(MesProCardSaveReqVO createReqVO) {
         // 1. 鏍¢獙鍏宠仈鏁版嵁
-        validateCardSaveData(createReqVO);
+        MesProWorkOrderDO workOrder = validateCardSaveData(createReqVO);
 
         // 2. 鎻掑叆
         MesProCardDO card = BeanUtils.toBean(createReqVO, MesProCardDO.class)
                 .setStatus(MesProWorkOrderStatusEnum.PREPARE.getStatus());
         cardMapper.insert(card);
 
-        // 3. 鑷姩鐢熸垚鏉$爜
+        // 3. 鎸夊伐鍗曞伐搴� + 鏀剁巼鐢熸垚宸ュ簭璁板綍
+        generateCardProcesses(card.getId(), workOrder);
+
+        // 4. 鑷姩鐢熸垚鏉$爜
         barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.PROCARD.getValue(),
                 card.getId(), card.getCode(), card.getCode());
         return card.getId();
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public void updateCard(MesProCardSaveReqVO updateReqVO) {
         // 1.1 鏍¢獙瀛樺湪 + 鑽夌鐘舵��
-        validateCardExistsAndPrepare(updateReqVO.getId());
+        MesProCardDO card = validateCardExistsAndPrepareInternal(updateReqVO.getId());
         // 1.2 鏍¢獙鍏宠仈鏁版嵁
-        validateCardSaveData(updateReqVO);
+        MesProWorkOrderDO workOrder = validateCardSaveData(updateReqVO);
 
         // 2. 鏇存柊
         MesProCardDO updateObj = BeanUtils.toBean(updateReqVO, MesProCardDO.class);
         cardMapper.updateById(updateObj);
+
+        // 3. 鏇存崲浜嗙敓浜ц鍗曪細鍘熷伐搴忚褰曞凡澶辨晥锛屾寜鏂板伐鍗曢噸寤�
+        if (ObjUtil.notEqual(card.getWorkOrderId(), updateReqVO.getWorkOrderId())) {
+            cardProcessService.deleteCardProcessByCardId(card.getId());
+            generateCardProcesses(card.getId(), workOrder);
+        }
     }
 
     @Override
@@ -139,10 +162,15 @@
 
     @Override
     public void validateCardExistsAndPrepare(Long id) {
+        validateCardExistsAndPrepareInternal(id);
+    }
+
+    private MesProCardDO validateCardExistsAndPrepareInternal(Long id) {
         MesProCardDO card = validateCardExistsInternal(id);
         if (ObjUtil.notEqual(MesProWorkOrderStatusEnum.PREPARE.getStatus(), card.getStatus())) {
             throw exception(PRO_CARD_NOT_PREPARE);
         }
+        return card;
     }
 
     private MesProCardDO validateCardExistsInternal(Long id) {
@@ -174,7 +202,7 @@
         }
     }
 
-    private void validateCardSaveData(MesProCardSaveReqVO reqVO) {
+    private MesProWorkOrderDO validateCardSaveData(MesProCardSaveReqVO reqVO) {
         // 鏍¢獙缂栫爜鍞竴
         validateCardCodeUnique(reqVO.getId(), reqVO.getCode());
         // 鏍¢獙宸ュ崟瀛樺湪
@@ -184,6 +212,61 @@
         if (ObjUtil.notEqual(workOrder.getProductId(), reqVO.getItemId())) {
             throw exception(PRO_WORK_ORDER_PRODUCT_MISMATCH);
         }
+        return workOrder;
+    }
+
+    /**
+     * 鎸夊伐鍗曞伐搴忎笌宸ュ簭鏀剁巼鐢熸垚娴佽浆鍗″伐搴忚褰�
+     *
+     * <p>鏁伴噺鍙e緞涓庝竴閿帓浜т竴鑷达紙瑙� MesProBatchScheduleService#calcTargetQuantities锛夛細
+     * 鏈亾宸ュ簭浜у嚭 = 宸ュ崟璁″垝鏁伴噺锛屽墠闈㈠悇閬撻�愮骇鏀惧ぇ鍚庡悜涓婂彇鏁达紱
+     * 鏈亾鎶曞叆 = 涓婇亾浜у嚭锛堥閬撴姇鍏� = 棣栭亾浜у嚭 / 鏀剁巼锛屽悜涓婂彇鏁达級锛屼笉鍚堟牸鍝� = 鎶曞叆 - 浜у嚭銆�
+     *
+     * <p>杩涘叆/鍑哄伐搴忔椂闂淬�佸伐浣嶃�佹搷浣滀汉鐣欑┖锛屽緟鐢熶骇瀹為檯鍙戠敓鏃跺~鍐欍��
+     */
+    private void generateCardProcesses(Long cardId, MesProWorkOrderDO workOrder) {
+        List<MesProWorkOrderProcessDO> processes = workOrderProcessService
+                .getWorkOrderProcessListByWorkOrderId(workOrder.getId());
+        if (CollUtil.isEmpty(processes) || workOrder.getQuantity() == null) {
+            return; // 宸ュ崟鏈淮鎶ゅ伐搴忔垨鏁伴噺缂哄け锛屽伐搴忚褰曠暀寰呮墜宸ョ淮鎶�
+        }
+        processes = new ArrayList<>(processes);
+        processes.sort(Comparator.comparing(MesProWorkOrderProcessDO::getSort,
+                Comparator.nullsLast(Comparator.naturalOrder())));
+
+        // 1. 鎸夋敹鐜囦粠鏈亾寰�鍓嶅�掓帹鍚勯亾浜у嚭閲忥紙鍚戜笂鍙栨暣涓烘暣鏁颁欢锛�
+        int size = processes.size();
+        BigDecimal[] outputs = new BigDecimal[size];
+        BigDecimal cumulativeYield = BigDecimal.ONE;
+        for (int i = size - 1; i >= 0; i--) {
+            outputs[i] = workOrder.getQuantity().divide(cumulativeYield, 0, RoundingMode.CEILING);
+            BigDecimal yieldRate = processes.get(i).getYieldRate();
+            if (yieldRate != null && yieldRate.signum() > 0) {
+                cumulativeYield = cumulativeYield.multiply(yieldRate);
+            }
+        }
+
+        // 2. 閫愰亾鐢熸垚璁板綍锛氭姇鍏� = 涓婇亾浜у嚭锛堥閬� = 鏈亾浜у嚭 / 鏀剁巼锛屽悜涓婂彇鏁达級
+        List<MesProCardProcessDO> cardProcesses = new ArrayList<>(size);
+        BigDecimal previousOutput = null;
+        for (int i = 0; i < size; i++) {
+            MesProWorkOrderProcessDO process = processes.get(i);
+            BigDecimal input;
+            if (previousOutput != null) {
+                input = previousOutput;
+            } else {
+                BigDecimal firstYield = process.getYieldRate();
+                input = firstYield == null || firstYield.signum() <= 0
+                        ? outputs[i] : outputs[i].divide(firstYield, 0, RoundingMode.CEILING);
+            }
+            cardProcesses.add(MesProCardProcessDO.builder()
+                    .cardId(cardId).sort(process.getSort()).processId(process.getProcessId())
+                    .inputQuantity(input).outputQuantity(outputs[i])
+                    .unqualifiedQuantity(BigDecimal.ZERO)
+                    .build());
+            previousOutput = outputs[i];
+        }
+        cardProcessService.createCardProcessBatch(cardProcesses);
     }
 
 }

--
Gitblit v1.9.3