From 400881f9103218313c552b254c8312b54a24f563 Mon Sep 17 00:00:00 2001
From: cl <1442464845@qq.com>
Date: 星期五, 08 五月 2026 12:36:59 +0800
Subject: [PATCH] 转历史单优化

---
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java |  448 +++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 283 insertions(+), 165 deletions(-)

diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
index 0b2102a..c679e2b 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -994,8 +994,11 @@
         if (!taskService.updateById(task)) {
             throw new CoolException("浠诲姟鐘舵�佷慨鏀瑰け璐ワ紒锛�");
         }
-        // 9.1 鍏�/鍑哄簱缁撴灉涓婃姤锛氭嫞鏂欏啀鍏ュ簱/鐩樼偣鍐嶅叆搴撳畬鎴愬悗閫氱煡浜戜粨锛堜笌瀹氭椂浠诲姟闂幆涓�鑷达級
-        reportInOutResultToCloud(task, loc, taskItems, null, true);
+        // 鐩樼偣鍐嶅叆搴撲笂鎶ヤ簯浠撳叆搴撳畬鎴愶紱鎷f枡鍐嶅叆搴撹烦杩囷紙鍏ュ簱渚� qty 鍙� anfme 涓烘墭鐩樹綑閲忥紱浜戜粨鍑哄簱瀹炲彂鍦ㄥ嚭搴撳畬鎴愪晶锛�
+        // reportInOutResultToCloud(task, loc, taskItems, null, true);
+        if (!TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType())) {
+            reportInOutResultToCloud(task, loc, taskItems, null, true);
+        }
     }
 
     /**
@@ -1477,6 +1480,7 @@
                         log.debug("[鎷f枡鍏ュ簱] 璁$畻鍚� pickedQty={}, minQty(鍓╀綑)={}, 灏嗘洿鏂� taskItem.anfme={}, taskItem.qty={}",
                                 pickedQty, minQty, minQty, pickedQty);
                         if (QuantityUtils.isNonNegative(minQty)) {
+                            enqueueCloudWmsOutNotifyLogEarly(task, taskItem, QuantityUtils.toScaledBigDecimal(pickedQty));
                             taskItem.setAnfme(minQty);
                             taskItem.setQty(pickedQty);
                             if (!taskItemService.updateById(taskItem)) {
@@ -1612,6 +1616,8 @@
         if (allItems.isEmpty()) {
             throw new CoolException("浠诲姟鏄庣粏涓虹┖");
         }
+        List<Long> allItemIds = allItems.stream().map(TaskItem::getId).filter(Objects::nonNull).collect(Collectors.toList());
+        Map<Long, BigDecimal> preQtyByItem = cloudWmsNotifyLogService.mapOutQtyFromInOutNotifyLogByTaskItemIds(allItemIds);
         Long loginUserId = SystemAuthUtils.getLoginUserId();
         if (loginUserId == null) {
             loginUserId = 1L;
@@ -1628,7 +1634,15 @@
         Map<String, Double> remainderByKey = new LinkedHashMap<>();
         for (Map.Entry<String, List<TaskItem>> e : byKey.entrySet()) {
             List<TaskItem> group = e.getValue();
-            double totalQty = group.stream().mapToDouble(ti -> ti.getQty() != null && ti.getQty() > 0 ? ti.getQty() : (ti.getAnfme() != null ? ti.getAnfme() : 0)).sum();
+            BigDecimal totalBd = BigDecimal.ZERO;
+            for (TaskItem ti : group) {
+                BigDecimal q = preQtyByItem.get(ti.getId());
+                if (q == null) {
+                    throw new CoolException("浜戜粨寰呭姙鏃犲嚭搴撴暟閲忥紝taskItemId=" + ti.getId());
+                }
+                totalBd = totalBd.add(q);
+            }
+            double totalQty = totalBd.setScale(6, RoundingMode.HALF_UP).doubleValue();
             TaskItem rep = group.get(0);
             TaskItem forDeduct = new TaskItem();
             forDeduct.setMatnrId(rep.getMatnrId()).setBatch(rep.getBatch()).setFieldsIndex(rep.getFieldsIndex()).setQty(totalQty);
@@ -1694,10 +1708,16 @@
                 if (group == null || group.isEmpty()) continue;
                 TaskItem rep = group.get(0);
                 TaskItem ti = new TaskItem();
-                ti.setTaskId(pickInTask.getId());
-                ti.setMatnrId(rep.getMatnrId()).setMaktx(rep.getMaktx()).setMatnrCode(rep.getMatnrCode());
-                ti.setBatch(rep.getBatch()).setFieldsIndex(rep.getFieldsIndex()).setUnit(rep.getUnit()).setSpec(rep.getSpec()).setModel(rep.getModel());
-                ti.setAnfme(rem).setQty(0.0);
+                BeanUtils.copyProperties(rep, ti);
+                ti.setId(null)
+                        .setTaskId(pickInTask.getId())
+                        .setAnfme(rem)
+                        .setQty(0.0)
+                        .setWorkQty(0.0)
+                        .setCreateBy(loginUserId)
+                        .setUpdateBy(loginUserId)
+                        .setCreateTime(new Date())
+                        .setUpdateTime(new Date());
                 taskItemService.save(ti);
                 LocItemWorking w = new LocItemWorking();
                 w.setTaskId(pickInTask.getId());
@@ -1970,7 +1990,18 @@
         if (StringUtils.isBlank(ruleCode)) {
             throw new CoolException("褰撳墠涓氬姟锛�" + SerialRuleCode.SYS_STOCK_CODE + "锛岀紪鐮佽鍒欎笉瀛樺湪锛侊紒");
         }
-        Double sum = taskItems.stream().mapToDouble(TaskItem::getAnfme).sum();
+        List<Long> itemIds = taskItems.stream().map(TaskItem::getId).filter(Objects::nonNull).collect(Collectors.toList());
+        Map<Long, BigDecimal> preMap = cloudWmsNotifyLogService.mapOutQtyFromInOutNotifyLogByTaskItemIds(itemIds);
+        BigDecimal sumBd = BigDecimal.ZERO;
+        for (TaskItem ti : taskItems) {
+            BigDecimal q = preMap.get(ti.getId());
+            if (q == null) {
+                throw new CoolException("浜戜粨寰呭姙鏃犲嚭搴撴暟閲忥紝taskItemId=" + ti.getId());
+            }
+            sumBd = sumBd.add(q);
+        }
+        sumBd = sumBd.setScale(6, RoundingMode.HALF_UP);
+        Double sum = sumBd.doubleValue();
         stock.setCode(ruleCode)
                 .setUpdateBy(loginUserId)
                 .setUpdateTime(new Date())
@@ -1983,22 +2014,26 @@
                 WkOrder wkOrder = asnOrderService.getById(orderId);
                 if (wkOrder != null) {
                     Double curQty = wkOrder.getQty() != null ? wkOrder.getQty() : 0.0;
-                    Double newQty = QuantityUtils.roundToScale(curQty + sum);
-                    wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val).setQty(newQty);
+                    BigDecimal newQtyBd = BigDecimal.valueOf(curQty).add(sumBd).setScale(6, RoundingMode.HALF_UP);
+                    wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val).setQty(newQtyBd.doubleValue());
                     if (!asnOrderService.updateById(wkOrder)) {
                         throw new CoolException("鍑哄簱鍗曞畬鎴愭暟閲忔洿鏂板け璐ワ紒锛�");
                     }
                 }
-                // 鎸夊嚭搴撳崟鏄庣粏姹囨�绘湰娆′换鍔℃暟閲忥紝鏇存柊鍚勬槑缁� workQty
-                Map<Long, Double> sumByOrderItemId = taskItems.stream()
-                        .filter(ti -> ti.getOrderItemId() != null)
-                        .collect(Collectors.groupingBy(TaskItem::getOrderItemId,
-                                Collectors.summingDouble(ti -> ti.getAnfme() != null ? ti.getAnfme() : 0.0)));
-                for (Map.Entry<Long, Double> e : sumByOrderItemId.entrySet()) {
+                Map<Long, BigDecimal> sumByOrderItemId = new HashMap<>();
+                for (TaskItem ti : taskItems) {
+                    if (ti.getOrderItemId() == null) {
+                        continue;
+                    }
+                    BigDecimal q = preMap.get(ti.getId());
+                    sumByOrderItemId.merge(ti.getOrderItemId(), q, BigDecimal::add);
+                }
+                for (Map.Entry<Long, BigDecimal> e : sumByOrderItemId.entrySet()) {
                     WkOrderItem oi = outStockItemService.getById(e.getKey());
                     if (oi != null) {
                         Double wq = oi.getWorkQty() != null ? oi.getWorkQty() : 0.0;
-                        oi.setWorkQty(QuantityUtils.roundToScale(wq + e.getValue()));
+                        BigDecimal nwq = BigDecimal.valueOf(wq).add(e.getValue()).setScale(6, RoundingMode.HALF_UP);
+                        oi.setWorkQty(nwq.doubleValue());
                         if (!outStockItemService.updateById(oi)) {
                             throw new CoolException("鍑哄簱鍗曟槑缁嗘墽琛屾暟閲忔洿鏂板け璐ワ紒锛�");
                         }
@@ -2008,7 +2043,7 @@
         } else if (!Objects.isNull(orderItem) && StringUtils.isNotBlank(orderItem.getId() + "")) {
             WkOrder wkOrder = asnOrderService.getById(orderItem.getOrderId());
             double curHeaderQty = wkOrder.getQty() != null ? wkOrder.getQty() : 0.0;
-            Double qty = Math.round((curHeaderQty + sum) * 1000000) / 1000000.0;
+            Double qty = QuantityUtils.roundToScale(QuantityUtils.add(curHeaderQty, sum));
             wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val)
                     .setQty(qty);
             if (!asnOrderService.updateById(wkOrder)) {
@@ -2032,6 +2067,7 @@
             /**閫氳繃浠诲姟鏄庣粏涓殑taskId鏌ヨ,鑾峰彇TASK鐨勭洰鏍囧簱浣嶄俊鎭�*/
             StockItem stockItem = new StockItem();
             BeanUtils.copyProperties(item, stockItem);
+            stockItem.setAnfme(QuantityUtils.roundToScale(preMap.get(item.getId())));
             stockItem.setSourceItemId(item.getOrderItemId())
                     .setUpdateBy(loginUserId)
                     .setUpdateTime(new Date())
@@ -2854,6 +2890,32 @@
         }
     }
 
+    @Override
+    public void enqueueCloudWmsOutNotifyLogEarly(Task task, TaskItem taskItem, BigDecimal outQty) {
+        if (task == null || taskItem == null || outQty == null) {
+            return;
+        }
+        try {
+            Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getOrgLoc()));
+            if (loc == null) {
+                return;
+            }
+            CloudInOutReportContext ctx = loadCloudInOutReportContext(task, loc, Collections.singletonList(taskItem), null, false);
+            if (ctx == null) {
+                return;
+            }
+            InOutResultReportParam param = buildInOutParamForItem(task, taskItem, false, outQty, ctx);
+            if (param == null) {
+                return;
+            }
+            String mode = resolveCloudWmsInoutReportMode();
+            boolean sendHold = CloudWmsInoutReportMode.MANUAL.equals(mode) || CloudWmsInoutReportMode.WAIT_ORDER.equals(mode);
+            cloudWmsNotifyLogService.saveOrUpdateInOutNotifyEarly(param, task.getId(), taskItem.getId(), sendHold, taskItem.getTenantId());
+        } catch (Exception e) {
+            log.warn("浜戜粨9.1鏃〦nqueue澶辫触 taskId={} taskItemId={}锛歿}", task.getId(), taskItem.getId(), e.getMessage());
+        }
+    }
+
     /**
      * 9.1 鍏�/鍑哄簱缁撴灉涓婃姤寰呭姙
      * @param isInbound true 鍏ュ簱瀹屾垚锛宖alse 鍑哄簱瀹屾垚
@@ -2861,159 +2923,56 @@
      */
     private void reportInOutResultToCloud(Task task, Loc loc, List<TaskItem> taskItems, Set<Long> pkinItemIds, boolean isInbound) {
         try {
-            String locId = isInbound ? task.getTargLoc() : task.getOrgLoc();
-            String wareHouseId = null;
-            if (loc.getWarehouseId() != null) {
-                Warehouse wh = warehouseService.getById(loc.getWarehouseId());
-                if (wh != null) {
-                    wareHouseId = wh.getCode();
-                }
-            }
-            if (wareHouseId == null) {
-                log.warn("鍏�/鍑哄簱缁撴灉涓婃姤寰呭姙璺宠繃锛氫粨搴撶紪鐮佷负绌猴紝taskId={}", task.getId());
+            CloudInOutReportContext ctx = loadCloudInOutReportContext(task, loc, taskItems, pkinItemIds, isInbound);
+            if (ctx == null) {
                 return;
             }
-            Map<Long, String> sourceToOrderNo = new HashMap<>();
-            if (isInbound && pkinItemIds != null && !pkinItemIds.isEmpty()) {
-                List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().in(WaitPakinItem::getId, pkinItemIds));
-                for (WaitPakinItem p : pakinItems) {
-                    if (p.getAsnCode() != null) {
-                        sourceToOrderNo.put(p.getId(), p.getAsnCode());
-                    }
-                }
-            }
-            // 鍏ュ簱缁勬墭鍦烘櫙鍏佽鎸� WaitPakinItem.asnCode 鍏滃簳锛涘嚭搴撳厑璁告寜鍗� orderId+lineId锛堜簯浠� 8.3锛夊厹搴曪紝閬垮厤浠� plat_order_code 涓虹┖鏃惰璺宠繃
-            boolean hasOutboundCloudLine = !isInbound && taskItems.stream().anyMatch(ti ->
-                    ti != null && ti.getOrderId() != null && StringUtils.isNotBlank(ti.getPlatItemId()));
-            boolean hasCloudSource = taskItems.stream().anyMatch(this::hasCloudOrderRef)
-                    || (isInbound && !sourceToOrderNo.isEmpty())
-                    || hasOutboundCloudLine;
-            if (!hasCloudSource) {
-                log.info("鍏�/鍑哄簱缁撴灉涓婃姤寰呭姙璺宠繃锛氭棤浜戜粨鏉ユ簮鍗曟嵁锛宼askId={}", task.getId());
-                return;
-            }
-            Set<Long> orderIdSet = taskItems.stream()
-                    .filter(Objects::nonNull)
-                    .map(TaskItem::getOrderId)
-                    .filter(Objects::nonNull)
-                    .collect(Collectors.toSet());
-            Map<Long, WkOrder> orderById = new HashMap<>();
-            if (!orderIdSet.isEmpty()) {
-                for (WkOrder o : asnOrderService.listByIds(orderIdSet)) {
-                    if (o != null && o.getId() != null) {
-                        orderById.put(o.getId(), o);
-                    }
-                }
-            }
-            Set<String> orderCodeSet = new HashSet<>();
-            for (TaskItem ti : taskItems) {
-                if (ti == null) {
-                    continue;
-                }
-                String on = isInbound && ti.getSource() != null
-                        ? sourceToOrderNo.get(ti.getSource())
-                        : (ti.getPlatOrderCode() != null ? ti.getPlatOrderCode() : ti.getPlatWorkCode());
-                if (on == null && isInbound) {
-                    on = ti.getPlatOrderCode() != null ? ti.getPlatOrderCode() : ti.getPlatWorkCode();
-                }
-                if (on == null && !isInbound && ti.getOrderId() != null) {
-                    WkOrder o = orderById.get(ti.getOrderId());
-                    if (o != null) {
-                        on = StringUtils.isNotBlank(o.getPoCode()) ? o.getPoCode() : o.getCode();
-                    }
-                }
-                if (StringUtils.isNotBlank(on)) {
-                    orderCodeSet.add(on);
-                }
-            }
-            Map<String, WkOrder> orderByCode = new HashMap<>();
-            if (!orderCodeSet.isEmpty()) {
-                for (WkOrder o : asnOrderService.list(new LambdaQueryWrapper<WkOrder>().in(WkOrder::getCode, orderCodeSet))) {
-                    if (o != null && StringUtils.isNotBlank(o.getCode())) {
-                        orderByCode.put(o.getCode(), o);
-                    }
-                }
-                for (WkOrder o : asnOrderService.list(new LambdaQueryWrapper<WkOrder>().in(WkOrder::getPoCode, orderCodeSet))) {
-                    if (o != null && StringUtils.isNotBlank(o.getPoCode())) {
-                        orderByCode.putIfAbsent(o.getPoCode(), o);
-                    }
-                }
-            }
+            List<Long> reportItemIds = taskItems.stream().map(TaskItem::getId).filter(Objects::nonNull).collect(Collectors.toList());
+            Map<Long, BigDecimal> outQtyByItem = isInbound ? Collections.emptyMap()
+                    : cloudWmsNotifyLogService.mapOutQtyFromInOutNotifyLogByTaskItemIds(reportItemIds);
             ObjectMapper om = new ObjectMapper();
             Date now = new Date();
-            Map<String, List<InOutResultReportParam>> byOrder = new LinkedHashMap<>();
-            for (TaskItem item : taskItems) {
-                if (item == null) {
-                    continue;
-                }
-                boolean hasTaskItemCloudRef = hasCloudOrderRef(item);
-                boolean hasInboundAsnFallbackRef = isInbound
-                        && item.getSource() != null
-                        && StringUtils.isNotBlank(sourceToOrderNo.get(item.getSource()));
-                boolean hasOutboundCloudLineRef = !isInbound && item.getOrderId() != null && StringUtils.isNotBlank(item.getPlatItemId());
-                if (!hasTaskItemCloudRef && !hasInboundAsnFallbackRef && !hasOutboundCloudLineRef) {
-                    continue;
-                }
-                WkOrder asnOrder = null;
-                if (item.getOrderId() != null) {
-                    asnOrder = orderById.get(item.getOrderId());
-                }
-                String orderNo = isInbound ? sourceToOrderNo.get(item.getSource()) : (item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode());
-                if (orderNo == null && isInbound) {
-                    orderNo = item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode();
-                }
-                if (orderNo == null && !isInbound && asnOrder != null) {
-                    orderNo = StringUtils.isNotBlank(asnOrder.getPoCode()) ? asnOrder.getPoCode() : asnOrder.getCode();
-                }
-                if (orderNo == null || item.getMatnrCode() == null) {
-                    continue;
-                }
-                if (asnOrder == null) {
-                    asnOrder = orderByCode.get(orderNo);
-                }
-                InOutResultReportParam param = new InOutResultReportParam()
-                        .setOrderNo(orderNo)
-                        .setPlanNo(item.getPlatWorkCode())
-                        .setWkType(item.getWkType())
-                        .setUnitNo(item.getUnit())
-                        .setLineId(item.getPlatItemId())
-                        .setWareHouseId(wareHouseId)
-                        .setDocWarehouseNo(asnOrder != null ? asnOrder.getDocTaskWarehouseNo() : null)
-                        .setOrgNo(asnOrder != null ? asnOrder.getDocOrgNo() : null)
-                        .setInWarehouseNo(isInbound && asnOrder != null ? asnOrder.getDocInWarehouseNo() : null)
-                        .setOutWarehouseNo(!isInbound && asnOrder != null ? asnOrder.getDocOutWarehouseNo() : null)
-                        .setLocId(locId)
-                        .setMatNr(item.getMatnrCode())
-                        .setQty(item.getAnfme() != null ? String.valueOf(item.getAnfme()) : "0")
-                        .setBatch(item.getBatch())
-                        .setInbound(isInbound)
-                        .setBarcode(task.getBarcode());
-                byOrder.computeIfAbsent(orderNo, k -> new ArrayList<>()).add(param);
-            }
             String mode = resolveCloudWmsInoutReportMode();
             boolean sendHold = CloudWmsInoutReportMode.MANUAL.equals(mode) || CloudWmsInoutReportMode.WAIT_ORDER.equals(mode);
-            for (Map.Entry<String, List<InOutResultReportParam>> e : byOrder.entrySet()) {
-                String orderNo = e.getKey();
-                for (InOutResultReportParam param : e.getValue()) {
-                    try {
-                        String requestBody = om.writeValueAsString(param);
-                        CloudWmsNotifyLog notifyLog = new CloudWmsNotifyLog()
-                                .setReportType(cloudWmsNotifyLogService.getReportTypeInOutResult())
-                                .setRequestBody(requestBody)
-                                .setRetryCount(0)
-                                .setBizRef("taskId=" + task.getId() + ",orderNo=" + orderNo)
-                                .setCreateTime(now)
-                                .setUpdateTime(now)
-                                .setSourceOrderNo(orderNo)
-                                .setInboundFlag(isInbound ? 1 : 0)
-                                .setWareHouseCode(wareHouseId)
-                                .setSendHold(sendHold ? 1 : 0)
-                                .setSending(0);
-                        cloudWmsNotifyLogService.fillFromConfig(notifyLog);
-                        cloudWmsNotifyLogService.save(notifyLog);
-                    } catch (JsonProcessingException ex) {
-                        log.warn("鍏�/鍑哄簱缁撴灉涓婃姤寰呭姙钀藉簱澶辫触锛堜笉褰卞搷涓绘祦绋嬶級锛宼askId={}锛宱rderNo={}锛歿}", task.getId(), orderNo, ex.getMessage());
-                    }
+            for (TaskItem item : taskItems) {
+                if (item == null || item.getId() == null) {
+                    continue;
+                }
+                BigDecimal outboundQty = isInbound ? null : outQtyByItem.get(item.getId());
+                if (!isInbound && outboundQty == null) {
+                    log.warn("浜戜粨9.1璺宠繃锛氬緟鍔炴棤鍑哄簱鏁伴噺锛宼askId={}锛宼askItemId={}", task.getId(), item.getId());
+                    continue;
+                }
+                InOutResultReportParam param = buildInOutParamForItem(task, item, isInbound, outboundQty, ctx);
+                if (param == null) {
+                    continue;
+                }
+                if (!isInbound && cloudWmsNotifyLogService.hasInOutNotifyRowForTaskItem(item.getId(), false)) {
+                    continue;
+                }
+                if (isInbound && cloudWmsNotifyLogService.hasInOutNotifyRowForTaskItem(item.getId(), true)) {
+                    continue;
+                }
+                String orderNo = param.getOrderNo();
+                try {
+                    String requestBody = om.writeValueAsString(param);
+                    String bizRef = "taskId=" + task.getId() + ",taskItemId=" + item.getId() + ",orderNo=" + orderNo;
+                    CloudWmsNotifyLog notifyLog = new CloudWmsNotifyLog()
+                            .setReportType(cloudWmsNotifyLogService.getReportTypeInOutResult())
+                            .setRequestBody(requestBody)
+                            .setRetryCount(0)
+                            .setBizRef(bizRef)
+                            .setCreateTime(now)
+                            .setUpdateTime(now)
+                            .setSourceOrderNo(orderNo)
+                            .setInboundFlag(isInbound ? 1 : 0)
+                            .setWareHouseCode(ctx.wareHouseId)
+                            .setSendHold(sendHold ? 1 : 0)
+                            .setSending(0);
+                    cloudWmsNotifyLogService.fillFromConfig(notifyLog);
+                    cloudWmsNotifyLogService.save(notifyLog);
+                } catch (JsonProcessingException ex) {
+                    log.warn("鍏�/鍑哄簱缁撴灉涓婃姤寰呭姙钀藉簱澶辫触锛堜笉褰卞搷涓绘祦绋嬶級锛宼askId={}锛宱rderNo={}锛歿}", task.getId(), orderNo, ex.getMessage());
                 }
             }
         } catch (Exception e) {
@@ -3021,6 +2980,165 @@
         }
     }
 
+    private CloudInOutReportContext loadCloudInOutReportContext(Task task, Loc loc, List<TaskItem> taskItems, Set<Long> pkinItemIds, boolean isInbound) {
+        if (task == null || loc == null || taskItems == null || taskItems.isEmpty()) {
+            return null;
+        }
+        String locId = isInbound ? task.getTargLoc() : task.getOrgLoc();
+        String wareHouseId = null;
+        if (loc.getWarehouseId() != null) {
+            Warehouse wh = warehouseService.getById(loc.getWarehouseId());
+            if (wh != null) {
+                wareHouseId = wh.getCode();
+            }
+        }
+        if (wareHouseId == null) {
+            log.warn("鍏�/鍑哄簱缁撴灉涓婃姤寰呭姙璺宠繃锛氫粨搴撶紪鐮佷负绌猴紝taskId={}", task.getId());
+            return null;
+        }
+        Map<Long, String> sourceToOrderNo = new HashMap<>();
+        if (isInbound && pkinItemIds != null && !pkinItemIds.isEmpty()) {
+            List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().in(WaitPakinItem::getId, pkinItemIds));
+            for (WaitPakinItem p : pakinItems) {
+                if (p.getAsnCode() != null) {
+                    sourceToOrderNo.put(p.getId(), p.getAsnCode());
+                }
+            }
+        }
+        boolean hasOutboundCloudLine = !isInbound && taskItems.stream().anyMatch(ti ->
+                ti != null && ti.getOrderId() != null && StringUtils.isNotBlank(ti.getPlatItemId()));
+        boolean hasCloudSource = taskItems.stream().anyMatch(this::hasCloudOrderRef)
+                || (isInbound && !sourceToOrderNo.isEmpty())
+                || hasOutboundCloudLine;
+        if (!hasCloudSource) {
+            log.info("鍏�/鍑哄簱缁撴灉涓婃姤寰呭姙璺宠繃锛氭棤浜戜粨鏉ユ簮鍗曟嵁锛宼askId={}", task.getId());
+            return null;
+        }
+        Set<Long> orderIdSet = taskItems.stream()
+                .filter(Objects::nonNull)
+                .map(TaskItem::getOrderId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+        Map<Long, WkOrder> orderById = new HashMap<>();
+        if (!orderIdSet.isEmpty()) {
+            for (WkOrder o : asnOrderService.listByIds(orderIdSet)) {
+                if (o != null && o.getId() != null) {
+                    orderById.put(o.getId(), o);
+                }
+            }
+        }
+        Set<String> orderCodeSet = new HashSet<>();
+        for (TaskItem ti : taskItems) {
+            if (ti == null) {
+                continue;
+            }
+            String on = isInbound && ti.getSource() != null
+                    ? sourceToOrderNo.get(ti.getSource())
+                    : (ti.getPlatOrderCode() != null ? ti.getPlatOrderCode() : ti.getPlatWorkCode());
+            if (on == null && isInbound) {
+                on = ti.getPlatOrderCode() != null ? ti.getPlatOrderCode() : ti.getPlatWorkCode();
+            }
+            if (on == null && !isInbound && ti.getOrderId() != null) {
+                WkOrder o = orderById.get(ti.getOrderId());
+                if (o != null) {
+                    on = StringUtils.isNotBlank(o.getPoCode()) ? o.getPoCode() : o.getCode();
+                }
+            }
+            if (StringUtils.isNotBlank(on)) {
+                orderCodeSet.add(on);
+            }
+        }
+        Map<String, WkOrder> orderByCode = new HashMap<>();
+        if (!orderCodeSet.isEmpty()) {
+            for (WkOrder o : asnOrderService.list(new LambdaQueryWrapper<WkOrder>().in(WkOrder::getCode, orderCodeSet))) {
+                if (o != null && StringUtils.isNotBlank(o.getCode())) {
+                    orderByCode.put(o.getCode(), o);
+                }
+            }
+            for (WkOrder o : asnOrderService.list(new LambdaQueryWrapper<WkOrder>().in(WkOrder::getPoCode, orderCodeSet))) {
+                if (o != null && StringUtils.isNotBlank(o.getPoCode())) {
+                    orderByCode.putIfAbsent(o.getPoCode(), o);
+                }
+            }
+        }
+        return new CloudInOutReportContext(wareHouseId, locId, sourceToOrderNo, orderById, orderByCode);
+    }
+
+    private InOutResultReportParam buildInOutParamForItem(Task task, TaskItem item, boolean isInbound,
+            BigDecimal outboundQtyResolved, CloudInOutReportContext ctx) {
+        if (task == null || item == null || ctx == null) {
+            return null;
+        }
+        boolean hasTaskItemCloudRef = hasCloudOrderRef(item);
+        boolean hasInboundAsnFallbackRef = isInbound
+                && item.getSource() != null
+                && StringUtils.isNotBlank(ctx.sourceToOrderNo.get(item.getSource()));
+        boolean hasOutboundCloudLineRef = !isInbound && item.getOrderId() != null && StringUtils.isNotBlank(item.getPlatItemId());
+        if (!hasTaskItemCloudRef && !hasInboundAsnFallbackRef && !hasOutboundCloudLineRef) {
+            return null;
+        }
+        WkOrder asnOrder = null;
+        if (item.getOrderId() != null) {
+            asnOrder = ctx.orderById.get(item.getOrderId());
+        }
+        String orderNo = isInbound ? ctx.sourceToOrderNo.get(item.getSource()) : (item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode());
+        if (orderNo == null && isInbound) {
+            orderNo = item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode();
+        }
+        if (orderNo == null && !isInbound && asnOrder != null) {
+            orderNo = StringUtils.isNotBlank(asnOrder.getPoCode()) ? asnOrder.getPoCode() : asnOrder.getCode();
+        }
+        if (orderNo == null || item.getMatnrCode() == null) {
+            return null;
+        }
+        if (!isInbound && outboundQtyResolved == null) {
+            return null;
+        }
+        if (asnOrder == null) {
+            asnOrder = ctx.orderByCode.get(orderNo);
+        }
+        String qtyStr;
+        if (isInbound) {
+            qtyStr = item.getAnfme() != null ? QuantityUtils.toPlainQtyString(QuantityUtils.toScaledBigDecimal(item.getAnfme())) : "0";
+        } else {
+            qtyStr = QuantityUtils.toPlainQtyString(outboundQtyResolved);
+        }
+        return new InOutResultReportParam()
+                .setOrderNo(orderNo)
+                .setPlanNo(item.getPlatWorkCode())
+                .setWkType(item.getWkType())
+                .setUnitNo(item.getUnit())
+                .setLineId(item.getPlatItemId())
+                .setWareHouseId(ctx.wareHouseId)
+                .setDocWarehouseNo(asnOrder != null ? asnOrder.getDocTaskWarehouseNo() : null)
+                .setOrgNo(asnOrder != null ? asnOrder.getDocOrgNo() : null)
+                .setInWarehouseNo(isInbound && asnOrder != null ? asnOrder.getDocInWarehouseNo() : null)
+                .setOutWarehouseNo(!isInbound && asnOrder != null ? asnOrder.getDocOutWarehouseNo() : null)
+                .setLocId(ctx.locId)
+                .setMatNr(item.getMatnrCode())
+                .setQty(qtyStr)
+                .setBatch(item.getBatch())
+                .setInbound(isInbound)
+                .setBarcode(task.getBarcode());
+    }
+
+    private static final class CloudInOutReportContext {
+        final String wareHouseId;
+        final String locId;
+        final Map<Long, String> sourceToOrderNo;
+        final Map<Long, WkOrder> orderById;
+        final Map<String, WkOrder> orderByCode;
+
+        private CloudInOutReportContext(String wareHouseId, String locId, Map<Long, String> sourceToOrderNo,
+                Map<Long, WkOrder> orderById, Map<String, WkOrder> orderByCode) {
+            this.wareHouseId = wareHouseId;
+            this.locId = locId;
+            this.sourceToOrderNo = sourceToOrderNo;
+            this.orderById = orderById;
+            this.orderByCode = orderByCode;
+        }
+    }
+
     private boolean hasCloudOrderRef(TaskItem item) {
         if (item == null) {
             return false;

--
Gitblit v1.9.1