From cccbfadcb6e96c23a33c40c0687a27c2f6efa1db Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 09 十一月 2026 13:16:42 +0800
Subject: [PATCH] feat(seal): 添加印章详情及图片预览功能

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskServiceImpl.java |  125 +++++++++++++++++++++++++++++++++++++++--
 1 files changed, 119 insertions(+), 6 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskServiceImpl.java
index efaf298..e3f59e5 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/stocktaking/task/MesWmStockTakingTaskServiceImpl.java
@@ -8,10 +8,15 @@
 import cn.iocoder.yudao.module.mes.controller.admin.wm.stocktaking.task.vo.MesWmStockTakingTaskSaveReqVO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskDO;
 import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskLineDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stocktaking.task.MesWmStockTakingTaskResultDO;
 import cn.iocoder.yudao.module.mes.dal.mysql.wm.stocktaking.task.MesWmStockTakingTaskMapper;
+import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
 import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockTakingTaskStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
 import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
 import cn.iocoder.yudao.module.mes.service.wm.stocktaking.plan.MesWmStockTakingPlanService;
+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.system.api.user.AdminUserApi;
 import jakarta.annotation.Resource;
 import org.springframework.context.annotation.Lazy;
@@ -19,7 +24,13 @@
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
+import java.math.BigDecimal;
 import java.util.List;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@@ -28,7 +39,7 @@
 /**
  * MES 鐩樼偣浠诲姟 Service 瀹炵幇绫�
  *
- * @author 鑺嬮亾婧愮爜
+ * @author 瓒呯骇绠$悊鍛�
  */
 @Service
 @Validated
@@ -47,6 +58,9 @@
     @Lazy
     @Resource
     private MesWmStockTakingTaskResultService stockTakingTaskResultService;
+
+    @Resource
+    private MesWmTransactionService wmTransactionService;
 
     @Resource
     private AdminUserApi adminUserApi;
@@ -128,7 +142,7 @@
 
         // 3. 鏍规嵁鍐荤粨鏍囪瘑锛屽鐗╄祫杩涜鍐荤粨
         if (Boolean.TRUE.equals(task.getFrozen())) {
-            updateMaterialStockFrozen(lines, true);
+            updateMaterialStockFrozen(id, lines, true);
         }
     }
 
@@ -137,6 +151,7 @@
     public void finishStockTakingTask(Long id) {
         // 1. 鏍¢獙浠诲姟瀛樺湪涓斾负瀹℃壒涓姸鎬�
         MesWmStockTakingTaskDO task = validateStockTakingTaskExistsAndApproving(id);
+        validateAllLinesCounted(id);
 
         // 2. 鏇存柊浠诲姟鐘舵�佷负宸插畬鎴�
         stockTakingTaskMapper.updateById(new MesWmStockTakingTaskDO().setId(id)
@@ -145,7 +160,41 @@
         // 3. 瑙e喕搴撳瓨
         if (Boolean.TRUE.equals(task.getFrozen())) {
             List<MesWmStockTakingTaskLineDO> lines = stockTakingTaskLineService.getStockTakingTaskLineListByTaskId(id);
-            updateMaterialStockFrozen(lines, false);
+            updateMaterialStockFrozen(id, lines, false);
+        }
+        // 涓庡畬鎴愮姸鎬併�佽В鍐诲叡鐢ㄤ簨鍔★紱宸紓鍏ヨ处澶辫触鏃舵暣鍗曞洖婊氥��
+        processStockTakingDifference(id);
+    }
+
+    private void validateAllLinesCounted(Long taskId) {
+        List<MesWmStockTakingTaskLineDO> lines = stockTakingTaskLineService.getStockTakingTaskLineListByTaskId(taskId);
+        if (CollUtil.isEmpty(lines)) {
+            throw exception(WM_STOCK_TAKING_TASK_NO_LINE);
+        }
+        List<MesWmStockTakingTaskResultDO> results = stockTakingTaskResultService.getStockTakingTaskResultListByTaskId(taskId);
+        Map<Long, MesWmStockTakingTaskLineDO> lineMap = new HashMap<>();
+        lines.forEach(line -> lineMap.put(line.getId(), line));
+        Set<Long> counted = new HashSet<>();
+        for (MesWmStockTakingTaskResultDO result : results) {
+            MesWmStockTakingTaskLineDO line = lineMap.get(result.getLineId());
+            if (line == null || !ObjUtil.equal(result.getTaskId(), taskId)
+                    || !ObjUtil.equal(result.getMaterialStockId(), line.getMaterialStockId())
+                    || !ObjUtil.equal(result.getItemId(), line.getItemId())
+                    || !ObjUtil.equal(result.getBatchId(), line.getBatchId())
+                    || !ObjUtil.equal(result.getWarehouseId(), line.getWarehouseId())
+                    || !ObjUtil.equal(result.getLocationId(), line.getLocationId())
+                    || !ObjUtil.equal(result.getAreaId(), line.getAreaId())
+                    || !ObjUtil.equal(result.getQuantity(), line.getQuantity())
+                    || result.getTakingQuantity() == null || result.getTakingQuantity().signum() < 0
+                    || !counted.add(result.getLineId())) {
+                throw exception(WM_STOCK_TAKING_TASK_RESULT_LINE_INVALID);
+            }
+        }
+        List<Long> missing = new ArrayList<>();
+        lines.stream().map(MesWmStockTakingTaskLineDO::getId)
+                .filter(lineId -> !counted.contains(lineId)).forEach(missing::add);
+        if (!missing.isEmpty()) {
+            throw exception(WM_STOCK_TAKING_TASK_INCOMPLETE, missing);
         }
     }
 
@@ -160,7 +209,7 @@
         task.setStatus(MesWmStockTakingTaskStatusEnum.CANCELED.getStatus());
         stockTakingTaskMapper.updateById(task);
         if (Boolean.TRUE.equals(task.getFrozen())) {
-            updateMaterialStockFrozen(stockTakingTaskLineService.getStockTakingTaskLineListByTaskId(id), false);
+            updateMaterialStockFrozen(id, stockTakingTaskLineService.getStockTakingTaskLineListByTaskId(id), false);
         }
     }
 
@@ -201,13 +250,13 @@
         return stockTakingTaskMapper.selectPage(pageReqVO);
     }
 
-    private void updateMaterialStockFrozen(List<MesWmStockTakingTaskLineDO> lines, boolean frozen) {
+    private void updateMaterialStockFrozen(Long taskId, List<MesWmStockTakingTaskLineDO> lines, boolean frozen) {
         if (CollUtil.isEmpty(lines)) {
             return;
         }
         List<Long> materialStockIds = convertList(lines,
                 MesWmStockTakingTaskLineDO::getMaterialStockId, line -> line.getMaterialStockId() != null);
-        materialStockService.updateMaterialStockFrozen(materialStockIds, frozen);
+        materialStockService.setMaterialStockFreeze(materialStockIds, "STOCK_TAKING", taskId, frozen);
     }
 
     private void validateStockTakingTaskCodeUnique(Long id, String code) {
@@ -220,4 +269,68 @@
         }
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void processStockTakingDifference(Long id) {
+        // 1. 鏍¢獙浠诲姟瀛樺湪涓斿凡瀹屾垚
+        MesWmStockTakingTaskDO task = validateStockTakingTaskExists(id);
+        if (!MesWmStockTakingTaskStatusEnum.FINISHED.getStatus().equals(task.getStatus())) {
+            throw exception(WM_STOCK_TAKING_TASK_NOT_FINISHED);
+        }
+        // 鍘熷瓙璁ら锛涢噸澶嶈皟鐢ㄤ笉浼氶噸澶嶇敓鎴愮洏鐩�/鐩樹簭娴佹按銆�
+        if (stockTakingTaskMapper.claimDifferenceProcessing(id) == 0) {
+            return;
+        }
+
+        // 2. 鑾峰彇鐩樼偣缁撴灉鍒楄〃
+        List<MesWmStockTakingTaskResultDO> results = stockTakingTaskResultService.getStockTakingTaskResultListByTaskId(id);
+        if (CollUtil.isEmpty(results)) {
+            return; // 鏃犵洏鐐圭粨鏋滐紝鏃犻渶澶勭悊
+        }
+
+        // 3. 閬嶅巻缁撴灉锛屽鐞嗗樊寮�
+        for (MesWmStockTakingTaskResultDO result : results) {
+            BigDecimal bookQuantity = result.getQuantity();          // 璐﹂潰鏁伴噺
+            BigDecimal takingQuantity = result.getTakingQuantity(); // 鐩樼偣鏁伴噺
+
+            if (takingQuantity == null || bookQuantity == null) {
+                continue;
+            }
+
+            // 璁$畻宸紓锛氱洏鐐规暟閲� - 璐﹂潰鏁伴噺
+            BigDecimal difference = takingQuantity.subtract(bookQuantity);
+
+            if (difference.compareTo(BigDecimal.ZERO) == 0) {
+                continue; // 鏃犲樊寮傦紝璺宠繃
+            }
+
+            // 4. 鍒涘缓搴撳瓨璋冩暣浜嬪姟
+            MesWmTransactionSaveReqDTO transaction = new MesWmTransactionSaveReqDTO()
+                    .setItemId(result.getItemId())
+                    .setBatchId(result.getBatchId())
+                    .setBatchCode(result.getBatchCode())
+                    .setWarehouseId(result.getWarehouseId())
+                    .setLocationId(result.getLocationId())
+                    .setAreaId(result.getAreaId())
+                    .setMaterialStockId(result.getMaterialStockId())
+                    .setBizId(task.getId())
+                    .setBizCode(task.getCode())
+                    .setBizLineId(result.getLineId());
+
+            if (difference.compareTo(BigDecimal.ZERO) > 0) {
+                // 鐩樼泩锛氬簱瀛樺鍔�
+                transaction.setType(MesWmTransactionTypeEnum.IN.getType())
+                        .setQuantity(difference)
+                        .setBizType(MesBizTypeConstants.WM_STOCK_TAKING);
+            } else {
+                // 鐩樹簭锛氬簱瀛樺噺灏�
+                transaction.setType(MesWmTransactionTypeEnum.OUT.getType())
+                        .setQuantity(difference) // 鐩樹簭涓鸿礋鏁帮紝绗﹀悎鍑哄簱浜嬪姟鏂瑰悜
+                        .setBizType(MesBizTypeConstants.WM_STOCK_TAKING);
+            }
+
+            wmTransactionService.createTransaction(transaction);
+        }
+    }
+
 }

--
Gitblit v1.9.3