From 74ad846852f42b4e2258bfddd5c2a33cc1ce9847 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期六, 29 八月 2026 18:03:46 +0800
Subject: [PATCH] feat(mes): 新增工序等待时长和报工数量配置功能

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java |  157 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 157 insertions(+), 0 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java
index 100627f..a7bf199 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productreceipt/MesWmProductReceiptServiceImpl.java
@@ -8,18 +8,29 @@
 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productreceipt.vo.MesWmProductReceiptPageReqVO;
 import cn.iocoder.yudao.module.mes.controller.admin.wm.productreceipt.vo.MesWmProductReceiptSaveReqVO;
+import cn.iocoder.yudao.module.mes.controller.admin.wm.productreceipt.vo.MesWmProductReceiptStockReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productreceipt.MesWmProductReceiptDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productreceipt.MesWmProductReceiptDetailDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productreceipt.MesWmProductReceiptLineDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.productreceipt.MesWmProductReceiptDetailMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.productreceipt.MesWmProductReceiptLineMapper;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.productreceipt.MesWmProductReceiptMapper;
 import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
+import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
 import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductReceiptStatusEnum;
 import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
+import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
+import cn.iocoder.yudao.module.mes.service.pro.feedback.MesProFeedbackService;
 import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService;
+import cn.iocoder.yudao.module.mes.service.wm.productproduce.MesWmProductProduceLineService;
 import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
 import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
 import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
@@ -31,7 +42,9 @@
 import org.springframework.validation.annotation.Validated;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
@@ -45,6 +58,10 @@
 
     @Resource
     private MesWmProductReceiptMapper productReceiptMapper;
+    @Resource
+    private MesWmProductReceiptLineMapper productReceiptLineMapper;
+    @Resource
+    private MesWmProductReceiptDetailMapper productReceiptDetailMapper;
 
     @Resource
     private MesWmProductReceiptLineService productReceiptLineService;
@@ -60,6 +77,14 @@
     private MesWmWarehouseLocationService locationService;
     @Resource
     private MesWmWarehouseAreaService areaService;
+    @Resource
+    private MesWmProductProduceMapper productProduceMapper;
+    @Resource
+    private MesWmProductProduceLineService productProduceLineService;
+    @Resource
+    private MesProFeedbackService feedbackService;
+    @Resource
+    private MesMdAutoCodeRecordService autoCodeRecordService;
 
     @Override
     public Long createProductReceipt(MesWmProductReceiptSaveReqVO createReqVO) {
@@ -166,6 +191,8 @@
         if (ObjUtil.notEqual(MesWmProductReceiptStatusEnum.APPROVED.getStatus(), receipt.getStatus())) {
             throw exception(WM_PRODUCT_RECPT_STATUS_ERROR);
         }
+        // 鏈嬀閫夊叆搴撴垨鏈垎閰嶅畬鐨勬暟閲忛粯璁よˉ鍒颁笉鍚堟牸浠撳簱
+        supplementDefectDetails(receipt);
         // 鏍¢獙鏄庣粏闈炵┖
         List<MesWmProductReceiptDetailDO> details = productReceiptDetailService.getProductReceiptDetailListByRecptId(id);
         if (CollUtil.isEmpty(details)) {
@@ -180,6 +207,136 @@
                 .setId(id).setStatus(MesWmProductReceiptStatusEnum.FINISHED.getStatus()));
     }
 
+    /**
+     * 涓烘湭鍕鹃�夊叆搴擄紙is_stock=false/绌猴級鎴栧垎閰嶆暟閲忎笉瓒崇殑琛岃ˉ涓�鏉′笉鍚堟牸浠撳簱鏄庣粏
+     *
+     * <p>姣忚鍓╀綑鏁伴噺 = 琛屾敹璐ф暟閲� - 宸插垎閰嶆槑缁嗘暟閲忎箣鍜岋紝鍓╀綑 &gt; 0 鏃惰嚜鍔ㄦ彃鍏ヤ笉鍚堟牸浠撳簱涓夌骇鏄庣粏锛�
+     * 淇濊瘉鎵ц鍏ュ簱鏃朵竴涓暟閲忓搴斾竴鏉℃祦姘淬��
+     */
+    private void supplementDefectDetails(MesWmProductReceiptDO receipt) {
+        List<MesWmProductReceiptLineDO> lines = productReceiptLineService.getProductReceiptLineListByRecptId(receipt.getId());
+        for (MesWmProductReceiptLineDO line : lines) {
+            List<MesWmProductReceiptDetailDO> details = productReceiptDetailService.getProductReceiptDetailListByLineId(line.getId());
+            BigDecimal sumDetailQty = CollectionUtils.getSumValue(details,
+                    MesWmProductReceiptDetailDO::getQuantity, BigDecimal::add, BigDecimal.ZERO);
+            BigDecimal remaining = line.getQuantity().subtract(sumDetailQty);
+            if (remaining.compareTo(BigDecimal.ZERO) <= 0) {
+                continue;
+            }
+            // 鏌ヨ涓嶅悎鏍间粨搴撲笁绾э紙鎸夌紪鐮佺害瀹氳瘑鍒級
+            MesWmWarehouseDO defectWarehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.DEFECT_WAREHOUSE);
+            MesWmWarehouseLocationDO defectLocation = locationService.getWarehouseLocationByCode(MesWmWarehouseLocationDO.DEFECT_LOCATION);
+            MesWmWarehouseAreaDO defectArea = areaService.getWarehouseAreaByCode(MesWmWarehouseAreaDO.DEFECT_AREA);
+            if (defectWarehouse == null || defectLocation == null || defectArea == null) {
+                throw exception(WM_PRODUCT_RECPT_NO_DEFECT_WAREHOUSE);
+            }
+            productReceiptDetailMapper.insert(new MesWmProductReceiptDetailDO()
+                    .setLineId(line.getId())
+                    .setReceiptId(receipt.getId())
+                    .setItemId(line.getItemId())
+                    .setQuantity(remaining)
+                    .setBatchId(line.getBatchId())
+                    .setWarehouseId(defectWarehouse.getId())
+                    .setLocationId(defectLocation.getId())
+                    .setAreaId(defectArea.getId()));
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long createProductReceiptByFeedback(Long feedbackId) {
+        // 骞傜瓑锛氫竴娆℃姤宸ュ彧鐢熸垚涓�鏉′骇鍝佸叆搴撳崟
+        MesWmProductReceiptDO existing = productReceiptMapper.selectByFeedbackId(feedbackId);
+        if (existing != null) {
+            return existing.getId();
+        }
+        // 鏍¢獙鎶ュ伐瀛樺湪
+        MesProFeedbackDO feedback = feedbackService.validateFeedbackExists(feedbackId);
+        // 鐢熸垚缂栫爜骞舵彃鍏ュ叆搴撳崟
+        MesWmProductReceiptDO receipt = new MesWmProductReceiptDO()
+                .setCode(autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.PRODUCTRECPT_CODE.getCode()))
+                .setName("浜у搧鍏ュ簱-" + feedback.getCode())
+                .setWorkOrderId(feedback.getWorkOrderId())
+                .setItemId(feedback.getItemId())
+                .setFeedbackId(feedbackId)
+                .setReceiptDate(LocalDateTime.now())
+                .setStatus(MesWmProductReceiptStatusEnum.PREPARE.getStatus());
+        productReceiptMapper.insert(receipt);
+        // 浠庝骇鍑哄崟浜у嚭琛岀敓鎴愬叆搴撳崟琛岋紙鍚堟牸/涓嶅悎鏍煎垎琛岋紝璐ㄩ噺鐘舵�佸師鏍峰甫鍏ワ級
+        MesWmProductProduceDO produce = productProduceMapper.selectByFeedbackId(feedbackId);
+        if (produce != null) {
+            List<MesWmProductProduceLineDO> produceLines = productProduceLineService.getProductProduceLineListByProduceId(produce.getId());
+            for (MesWmProductProduceLineDO produceLine : produceLines) {
+                if (produceLine.getQuantity() == null || produceLine.getQuantity().compareTo(BigDecimal.ZERO) <= 0) {
+                    continue;
+                }
+                productReceiptLineMapper.insert(new MesWmProductReceiptLineDO()
+                        .setReceiptId(receipt.getId())
+                        .setItemId(produceLine.getItemId())
+                        .setQuantity(produceLine.getQuantity())
+                        .setBatchId(produceLine.getBatchId())
+                        .setBatchCode(produceLine.getBatchCode())
+                        .setQualityStatus(produceLine.getQualityStatus())
+                        .setIsStock(Boolean.FALSE));
+            }
+        }
+        return receipt.getId();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void submitStock(MesWmProductReceiptStockReqVO reqVO) {
+        // 鏍¢獙鍏ュ簱鍗曞瓨鍦ㄤ笖涓哄緟涓婃灦锛圓PPROVING锛�
+        MesWmProductReceiptDO receipt = validateProductReceiptExists(reqVO.getReceiptId());
+        if (ObjUtil.notEqual(MesWmProductReceiptStatusEnum.APPROVING.getStatus(), receipt.getStatus())) {
+            throw exception(WM_PRODUCT_RECPT_STATUS_ERROR);
+        }
+        List<MesWmProductReceiptStockReqVO.Row> rows = reqVO.getRows();
+        if (CollUtil.isEmpty(rows)) {
+            throw exception(WM_PRODUCT_RECPT_NO_LINE);
+        }
+        // 閫愯澶勭悊锛氭洿鏂版槸鍚﹀叆搴� + 閲嶅缓涓婃灦鏄庣粏
+        for (MesWmProductReceiptStockReqVO.Row row : rows) {
+            MesWmProductReceiptLineDO line = productReceiptLineMapper.selectById(row.getLineId());
+            if (line == null || !ObjUtil.equal(line.getReceiptId(), receipt.getId())) {
+                throw exception(WM_PRODUCT_RECPT_LINE_NOT_EXISTS);
+            }
+            Boolean isStock = Boolean.TRUE.equals(row.getIsStock());
+            productReceiptLineMapper.updateById(new MesWmProductReceiptLineDO()
+                    .setId(line.getId()).setIsStock(isStock));
+            // 鍒犻櫎璇ヨ鏃ф槑缁嗭紝閲嶅缓鍒嗛厤
+            productReceiptDetailService.deleteProductReceiptDetailByLineId(line.getId());
+            if (!isStock) {
+                continue; // 鏈嬀閫夛細涓嶅垎閰嶏紝鎵ц鍏ュ簱鏃惰嚜鍔ㄨ繘涓嶅悎鏍间粨搴�
+            }
+            // 鍕鹃�夊叆搴擄細鍒嗛厤鏁伴噺涔嬪拰蹇呴』绛変簬琛屾敹璐ф暟閲�
+            List<MesWmProductReceiptStockReqVO.Detail> details = row.getDetails();
+            if (CollUtil.isEmpty(details)) {
+                throw exception(WM_PRODUCT_RECPT_STOCK_QUANTITY_MISMATCH);
+            }
+            BigDecimal sumDetailQty = details.stream()
+                    .map(MesWmProductReceiptStockReqVO.Detail::getQuantity)
+                    .filter(Objects::nonNull)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            if (line.getQuantity() == null || sumDetailQty.compareTo(line.getQuantity()) != 0) {
+                throw exception(WM_PRODUCT_RECPT_STOCK_QUANTITY_MISMATCH);
+            }
+            // 鏍¢獙浠撳簱灞傜骇鍏崇郴骞舵彃鍏ユ槑缁�
+            for (MesWmProductReceiptStockReqVO.Detail detail : details) {
+                areaService.validateWarehouseAreaExists(detail.getWarehouseId(), detail.getLocationId(), detail.getAreaId());
+                productReceiptDetailMapper.insert(new MesWmProductReceiptDetailDO()
+                        .setLineId(line.getId())
+                        .setReceiptId(receipt.getId())
+                        .setItemId(line.getItemId())
+                        .setQuantity(detail.getQuantity())
+                        .setBatchId(line.getBatchId())
+                        .setWarehouseId(detail.getWarehouseId())
+                        .setLocationId(detail.getLocationId())
+                        .setAreaId(detail.getAreaId()));
+            }
+        }
+    }
+
     private void createTransactionList(MesWmProductReceiptDO receipt, List<MesWmProductReceiptDetailDO> details) {
         // 1. 鏌ヨ铏氭嫙绾胯竟搴�
         MesWmWarehouseDO virtualWarehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE);

--
Gitblit v1.9.3