From 43d6ae86bc229a1a75637fae33be378e105016e3 Mon Sep 17 00:00:00 2001
From: cl <1442464845@qq.com>
Date: 星期日, 29 三月 2026 20:47:11 +0800
Subject: [PATCH] RCS通知

---
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/RcsBusTaskNoticeServiceImpl.java |   75 ++++++++++
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java         |  128 +++++++++--------
 rsf-admin/src/page/task/TaskList.jsx                                                              |   18 ++
 rsf-server/src/main/java/com/vincent/rsf/server/api/entity/constant/RcsConstant.java              |    3 
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/RcsBusTaskNoticeService.java          |   14 ++
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java      |    2 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TaskStsType.java                    |  116 ++++++++--------
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java       |   30 ++++
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TaskService.java                  |    5 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TaskController.java            |    2 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java      |    2 
 11 files changed, 272 insertions(+), 123 deletions(-)

diff --git a/rsf-admin/src/page/task/TaskList.jsx b/rsf-admin/src/page/task/TaskList.jsx
index 1667f99..6f62394 100644
--- a/rsf-admin/src/page/task/TaskList.jsx
+++ b/rsf-admin/src/page/task/TaskList.jsx
@@ -372,6 +372,21 @@
     )
 }
 
+/** 鎷f枡/鐩樼偣鍑哄簱锛氫粎 RCS 鎵ц涓�(<198)鍙彇娑堬紱199銆�198 涓嶅彲鍙栨秷 */
+const canCancelPickOrCheckOut = (record) => {
+    if (record?.taskType != 103 && record?.taskType != 107) return false;
+    const s = record.taskStatus;
+    return s < 198;
+};
+
+/** 鏅�氬叆鍑哄簱銆佺┖鏉裤�佺Щ搴撶瓑锛氬垱寤烘�佸彲鍙栨秷锛�199 涓嶅彲鍙栨秷 */
+const canCancelLegacy = (record) => {
+    const t = record?.taskType;
+    const s = record?.taskStatus;
+    if (t != 1 && t != 101 && t != 10 && t != 11) return false;
+    return s == 1 || s == 101;
+};
+
 /**
  * 鍙栨秷鎸夐挳
  * @returns 
@@ -393,8 +408,9 @@
             notify(msg);
         }
     }
+    const showCancel = canCancelPickOrCheckOut(record) || canCancelLegacy(record);
     return (
-        (record.taskStatus == 1 || record.taskStatus == 101 || record.taskStatus == 199) && (record.taskType == 1 || record.taskType == 101 || record.taskType == 10 || record.taskType == 107 || record.taskType == 103 || record.taskType == 11) ?
+        showCancel ?
             <ConfirmButton
                 onConfirm={clickCancel}
                 startIcon={<CancelIcon />}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/constant/RcsConstant.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/constant/RcsConstant.java
index 7eddd2f..f1c6cae 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/constant/RcsConstant.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/entity/constant/RcsConstant.java
@@ -19,4 +19,7 @@
     
     //鍙栨秷RCS浠诲姟
     public static String cancelTask = "/api/open/task/cancel";
+
+    /** 浠诲姟鐘舵�佸弽鍚戦�氱煡 RCS锛圥OST body: taskNo, status锛� */
+    public static String TASK_STATUS_NOTICE = "/api/open/bus/notice";
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/RcsBusTaskNoticeService.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/RcsBusTaskNoticeService.java
new file mode 100644
index 0000000..7c9d01c
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/RcsBusTaskNoticeService.java
@@ -0,0 +1,14 @@
+package com.vincent.rsf.server.api.service;
+
+/**
+ * 绠$悊鍚庡彴瀵瑰伐浣滄。鐐广�屽畬鎴愩�嶆椂鍙嶅悜閫氱煡 RCS锛歅OST /api/open/bus/notice銆�
+ * 銆屽彇娑堛�嶄粎閫氳繃 RCS 鍙栨秷鎺ュ彛锛�/api/open/task/cancel锛夛紱PDA銆丷CS 鍥炶皟銆佸畾鏃朵换鍔$瓑涓嶈皟姝ゅ銆�
+ */
+public interface RcsBusTaskNoticeService {
+
+    /**
+     * @param taskNo  宸ヤ綔妗d换鍔$紪鐮�
+     * @param status  {@link com.vincent.rsf.server.manager.enums.TaskStsType} 鐨� id锛堝畬鎴� 98/198/200锛夛紱鍙栨秷璧� RCS 鍙栨秷鎺ュ彛锛屼笉鐢ㄦ湰鎺ュ彛
+     */
+    void notifyTaskStatus(String taskNo, Integer status);
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
index fb2e32f..5c324d6 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
@@ -191,7 +191,7 @@
             }
             if (first.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) {
                 for (Task task : tasks) {
-                    taskService.completeFullOutStock(task.getId(), loginUserId);
+                    taskService.completeFullOutStock(task.getId(), loginUserId, false);
                 }
                 return R.ok("纭鎴愬姛锛屽叏鐗堝嚭搴撳凡瀹屾垚");
             }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/RcsBusTaskNoticeServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/RcsBusTaskNoticeServiceImpl.java
new file mode 100644
index 0000000..7ed6dd3
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/RcsBusTaskNoticeServiceImpl.java
@@ -0,0 +1,75 @@
+package com.vincent.rsf.server.api.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.cfg.CoercionAction;
+import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
+import com.vincent.rsf.server.api.config.RemotesInfoProperties;
+import com.vincent.rsf.server.api.entity.CommonResponse;
+import com.vincent.rsf.server.api.entity.constant.RcsConstant;
+import com.vincent.rsf.server.api.service.RcsBusTaskNoticeService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** 绠$悊鍚庡彴宸ヤ綔妗e畬鎴�/鍙栨秷鏃堕�氱煡 RCS */
+@Slf4j
+@Service
+public class RcsBusTaskNoticeServiceImpl implements RcsBusTaskNoticeService {
+
+    @Autowired(required = false)
+    private RemotesInfoProperties.RcsApi rcsApi;
+    @Autowired(required = false)
+    private RestTemplate restTemplate;
+
+    @Override
+    public void notifyTaskStatus(String taskNo, Integer status) {
+        if (StringUtils.isBlank(taskNo) || status == null) {
+            return;
+        }
+        if (rcsApi == null || StringUtils.isBlank(rcsApi.getHost()) || StringUtils.isBlank(rcsApi.getPort())) {
+            log.debug("璺宠繃 RCS 浠诲姟鐘舵�侀�氱煡锛氭湭閰嶇疆 platform.rcs");
+            return;
+        }
+        if (restTemplate == null) {
+            log.warn("璺宠繃 RCS 浠诲姟鐘舵�侀�氱煡锛歊estTemplate 鏈敞鍏�");
+            return;
+        }
+        String url = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.TASK_STATUS_NOTICE;
+        Map<String, String> body = new HashMap<>(2);
+        body.put("taskNo", taskNo);
+        body.put("status", String.valueOf(status));
+        try {
+            HttpHeaders headers = new HttpHeaders();
+            headers.add("Content-Type", "application/json");
+            headers.add("api-version", "v2.0");
+            HttpEntity<Map<String, String>> entity = new HttpEntity<>(body, headers);
+            log.info("RCS 浠诲姟鐘舵�侀�氱煡 POST {} body={}", url, JSONObject.toJSONString(body));
+            ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
+            if (exchange.getBody() == null) {
+                log.warn("RCS 浠诲姟鐘舵�侀�氱煡鍝嶅簲浣撲负绌� taskNo={}", taskNo);
+                return;
+            }
+            ObjectMapper om = new ObjectMapper();
+            om.coercionConfigDefaults().setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
+            CommonResponse res = om.readValue(exchange.getBody(), CommonResponse.class);
+            if (res.getCode() != null && res.getCode() == 200) {
+                log.info("RCS 浠诲姟鐘舵�侀�氱煡鎴愬姛 taskNo={} status={}", taskNo, status);
+            } else {
+                log.warn("RCS 浠诲姟鐘舵�侀�氱煡闈炴垚鍔� taskNo={} status={} code={} msg={}",
+                        taskNo, status, res.getCode(), res.getMsg());
+            }
+        } catch (Exception e) {
+            log.warn("RCS 浠诲姟鐘舵�侀�氱煡寮傚父 taskNo={} status={}锛歿}", taskNo, status, e.getMessage());
+        }
+    }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
index a1b887c..90b7bdd 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
@@ -118,7 +118,34 @@
     private WarehouseAreasItemService warehouseAreasItemService;
     @Autowired
     private ConfigService configService;
+    @Autowired
+    private TaskItemService taskItemService;
+    @Autowired
+    private TaskService taskService;
 
+    /**
+     * 浜戜粨鏀瑰崟/鍙栨秷鍓嶏細浠诲姟鏄庣粏宸插叧鑱旇鍗曟嵁涓斾富浠诲姟鏈�昏緫鍒犻櫎鍒欎笉鍏佽
+     */
+    private void assertWkOrderNoLinkedTask(Long wkOrderId) {
+        if (wkOrderId == null) {
+            return;
+        }
+        List<TaskItem> links = taskItemService.list(new LambdaQueryWrapper<TaskItem>()
+                .select(TaskItem::getTaskId)
+                .and(w -> w.eq(TaskItem::getOrderId, wkOrderId)
+                        .or(o -> o.eq(TaskItem::getSourceId, wkOrderId)
+                                .eq(TaskItem::getOrderType, OrderType.ORDER_OUT.type))));
+        if (links.isEmpty()) {
+            return;
+        }
+        Set<Long> taskIds = links.stream().map(TaskItem::getTaskId).filter(Objects::nonNull).collect(Collectors.toSet());
+        if (taskIds.isEmpty()) {
+            return;
+        }
+        if (taskService.count(new LambdaQueryWrapper<Task>().in(Task::getId, taskIds)) > 0) {
+            throw new CoolException("璇ュ崟鎹凡鐢熸垚浠诲姟锛屼笉鍙慨鏀广�佸彇娑堟垨鍒犻櫎锛侊紒");
+        }
+    }
 
     /**
      * @author Ryan
@@ -465,6 +492,7 @@
                     WkOrder order = asnOrderService.getOne(new LambdaQueryWrapper<WkOrder>()
                             .eq(WkOrder::getPoCode, syncOrder.getOrderInternalCode()));
                     if (!Objects.isNull(order)) {
+                        assertWkOrderNoLinkedTask(order.getId());
                         // 浠呮湭鎵ц鐘舵�佸彲琚� order/add 淇敼锛堝叆搴撴湭鎵ц銆佸嚭搴撲换鍔″垵濮嬶級
                         List<Short> editableStatus = Arrays.asList(AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val
                                 ,AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val
@@ -943,6 +971,7 @@
             if (Objects.isNull(wkOrder)) {
                 throw new CoolException("璇风‘璁ゅ崟鎹細" + order.getOrderNo() + "鏄惁宸茬粡鎵ц鎴栨槸鍚﹀悓姝ワ紒锛�");
             }
+            assertWkOrderNoLinkedTask(wkOrder.getId());
             order.getOrderItems().forEach(orderItem -> {
                 WkOrderItem wkOrderItem = asnOrderItemService.getOne(new LambdaUpdateWrapper<WkOrderItem>()
                         .eq(WkOrderItem::getMatnrCode, orderItem.getMatnr())
@@ -1006,6 +1035,7 @@
                 throw new CoolException("鍗曟嵁涓嶅瓨鍦紝鏃犳硶鍙栨秷锛侊紒璇锋彁渚涘崟鎹唴鐮�(orderInternalCode)鎴栧崟鍙�(orderNo)銆�");
             }
             final WkOrder finalWkOrder = wkOrder;
+            assertWkOrderNoLinkedTask(finalWkOrder.getId());
             // 宸茬粍鎵樹笉鍙彇娑�
             long pakinCount = waitPakinItemService.count(new LambdaQueryWrapper<WaitPakinItem>()
                     .eq(WaitPakinItem::getAsnId, finalWkOrder.getId()));
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TaskController.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TaskController.java
index ea42f39..5fa1a15 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TaskController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/TaskController.java
@@ -138,7 +138,7 @@
         if (Cools.isEmpty(id)) {
             throw new CoolException("鍙傛暟涓嶈兘涓虹┖锛侊紒");
         }
-        return R.ok("鍏ㄧ増鍑哄簱瀹岀粨鎴愬姛").add(taskService.completeFullOutStock(id, getLoginUserId()));
+        return R.ok("鍏ㄧ増鍑哄簱瀹岀粨鎴愬姛").add(taskService.completeFullOutStock(id, getLoginUserId(), true));
     }
 
     /**
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TaskStsType.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TaskStsType.java
index 4bcac1f..72c67dc 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TaskStsType.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/TaskStsType.java
@@ -1,58 +1,58 @@
-package com.vincent.rsf.server.manager.enums;
-
-public enum TaskStsType {
-    //浠诲姟鐘舵��
-    GENERATE_IN("1", "鍒涘缓鍏ュ簱浠诲姟"),
-    WCS_EXECUTE_IN("2", "RCS浠诲姟宸蹭笅鍙�"),
-    WCS_CONTAINER_RECEIVE("3", "RCS瀹瑰櫒鍒拌揪"),
-    WCS_CONVEYOR_START("4", "RCS瀹瑰櫒娴佸姩浠诲姟宸蹭笅鍙�"),
-    WCS_TOTE_LOAD("5", "RCS鍙栫瀹屾垚"),
-    WCS_TOTE_UNLOAD("6", "RCS鏀剧瀹屾垚"),
-    WCS_PUTAWAY_SUCESS("7", "RCS浠诲姟瀹屾垚"),
-
-//    WCS_PUTAWAY_FAILED(11L, "浠诲姟澶辫触"),
-//
-//    WCS_PUTAWAY_CANCEL(12L, "浠诲姟鍙栨秷"),
-//
-//    WCS_PUTAWAY_SUSPEND(13L, "鍏ュ簱浠诲姟鎸傝捣"),
-
-    COMPLETE_IN("98", "鍏ュ簱瀹屾垚"),
-
-    REPORT_IN("99", "涓婃姤瀹屾垚"),
-
-    UPDATED_IN("100", "搴撳瓨鏇存柊瀹屾垚"),
-
-    GENERATE_OUT("101", "鍒涘缓鍑哄簱浠诲姟"),
-
-    WCS_EXECUTE_OUT("102", "RCS鍑哄簱浠诲姟宸蹭笅鍙�"),
-
-    WCS_EXECUTE_OUT_TOTE_LOAD("103", "RCS鍙栫瀹屾垚"),
-
-    WCS_EXECUTE_OUT_TOTE_UNLOAD("104", "RCS鏀剧瀹屾垚"),
-
-    WCS_EXECUTE_OUT_TASK_DONE("105", "RCS浠诲姟瀹屾垚"),
-
-    WCS_EXECUTE_OUT_ARRIVED("106", "RCS瀹瑰櫒宸插埌杈�"),
-
-    WCS_EXECUTE_OUT_CONVEYOR("107", "RCS瀹瑰櫒娴佸姩浠诲姟宸蹭笅鍙�"),
-
-    AWAIT("196","绛夊緟纭"),
-
-    GENERATE_WAVE_SEED("197", "绛夊緟瀹瑰櫒鍒拌揪"),
-
-    COMPLETE_OUT("198", "鍑哄簱瀹屾垚"),
-
-    WAVE_SEED("199", "鎾涓�/鐩樼偣涓�/寰呯‘璁�"),
-
-    UPDATED_OUT("200", "搴撳瓨鏇存柊瀹屾垚"),
-    ;
-
-    public Integer id;
-    public String desc;
-
-    TaskStsType(String id, String desc) {
-        this.id = Integer.parseInt(id);
-        this.desc = desc;
-    }
-
-}
+package com.vincent.rsf.server.manager.enums;
+
+public enum TaskStsType {
+    //浠诲姟鐘舵��
+    GENERATE_IN("1", "鍒涘缓鍏ュ簱浠诲姟"),
+    WCS_EXECUTE_IN("2", "RCS浠诲姟宸蹭笅鍙�"),
+    WCS_CONTAINER_RECEIVE("3", "RCS瀹瑰櫒鍒拌揪"),
+    WCS_CONVEYOR_START("4", "RCS瀹瑰櫒娴佸姩浠诲姟宸蹭笅鍙�"),
+    WCS_TOTE_LOAD("5", "RCS鍙栫瀹屾垚"),
+    WCS_TOTE_UNLOAD("6", "RCS鏀剧瀹屾垚"),
+    WCS_PUTAWAY_SUCESS("7", "RCS浠诲姟瀹屾垚"),
+
+//    WCS_PUTAWAY_FAILED(11L, "浠诲姟澶辫触"),
+//
+//    WCS_PUTAWAY_CANCEL(12L, "浠诲姟鍙栨秷"),
+//
+//    WCS_PUTAWAY_SUSPEND(13L, "鍏ュ簱浠诲姟鎸傝捣"),
+
+    COMPLETE_IN("98", "鍏ュ簱瀹屾垚"),
+
+    REPORT_IN("99", "涓婃姤瀹屾垚"),
+
+    UPDATED_IN("100", "搴撳瓨鏇存柊瀹屾垚"),
+
+    GENERATE_OUT("101", "鍒涘缓鍑哄簱浠诲姟"),
+
+    WCS_EXECUTE_OUT("102", "RCS鍑哄簱浠诲姟宸蹭笅鍙�"),
+
+    WCS_EXECUTE_OUT_TOTE_LOAD("103", "RCS鍙栫瀹屾垚"),
+
+    WCS_EXECUTE_OUT_TOTE_UNLOAD("104", "RCS鏀剧瀹屾垚"),
+
+    WCS_EXECUTE_OUT_TASK_DONE("105", "RCS浠诲姟瀹屾垚"),
+
+    WCS_EXECUTE_OUT_ARRIVED("106", "RCS瀹瑰櫒宸插埌杈�"),
+
+    WCS_EXECUTE_OUT_CONVEYOR("107", "RCS瀹瑰櫒娴佸姩浠诲姟宸蹭笅鍙�"),
+
+    AWAIT("196","绛夊緟纭"),
+
+    GENERATE_WAVE_SEED("197", "绛夊緟瀹瑰櫒鍒拌揪"),
+
+    COMPLETE_OUT("198", "鍑哄簱瀹屾垚"),
+
+    WAVE_SEED("199", "鎾涓�/鐩樼偣涓�/寰呯‘璁�"),
+
+    UPDATED_OUT("200", "搴撳瓨鏇存柊瀹屾垚"),
+    ;
+
+    public Integer id;
+    public String desc;
+
+    TaskStsType(String id, String desc) {
+        this.id = Integer.parseInt(id);
+        this.desc = desc;
+    }
+
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java
index 48ae660..4b54290 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/MaterialAutoSchedules.java
@@ -307,7 +307,7 @@
                 continue;
             }
             try {
-                taskService.completeFullOutStock(task.getId(), SYSTEM_USER_ID);
+                taskService.completeFullOutStock(task.getId(), SYSTEM_USER_ID, false);
                 log.info("[鑷姩鎷h揣瀹屾垚] 浠诲姟: {}, 鏂欑: {}, 鐗╂枡: {} 宸茶嚜鍔ㄧ‘璁ゅ嚭搴撳苟鏇存柊搴撳瓨", task.getTaskCode(), task.getBarcode(), matnrCode);
             } catch (Exception e) {
                 log.warn("[鑷姩鎷h揣瀹屾垚] 浠诲姟: {} 澶勭悊澶辫触: {}", task.getTaskCode(), e.getMessage());
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TaskService.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TaskService.java
index dc8eecd..c1371d6 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TaskService.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/TaskService.java
@@ -28,7 +28,10 @@
 
     Task operateComplete(Long id, Long loginUserId);
 
-    Task completeFullOutStock(Long id, Long loginUserId);
+    /**
+     * @param notifyRcsFromAdmin true锛氱鐞嗗悗鍙般�屽叏鐗堝嚭搴撳畬缁撱�嶆帴鍙h皟鐢ㄦ椂閫氱煡 RCS锛沠alse锛氬畾鏃�/PDA 绛夊悓婧愪笉閫氱煡
+     */
+    Task completeFullOutStock(Long id, Long loginUserId, boolean notifyRcsFromAdmin);
 
     void moveToDeep(Long loginUserId, String curLoc) throws Exception;
 
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 a7197d7..6423c9f 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
@@ -13,6 +13,7 @@
 import com.vincent.rsf.server.api.config.RemotesInfoProperties;
 import com.vincent.rsf.server.api.controller.erp.params.InOutResultReportParam;
 import com.vincent.rsf.server.api.controller.erp.params.TaskInParam;
+import com.vincent.rsf.server.api.service.RcsBusTaskNoticeService;
 import com.vincent.rsf.server.api.entity.CommonResponse;
 import com.vincent.rsf.server.api.entity.constant.RcsConstant;
 import com.vincent.rsf.server.api.entity.dto.InTaskMsgDto;
@@ -131,6 +132,8 @@
     private CloudWmsNotifyLogService cloudWmsNotifyLogService;
     @Autowired
     private WarehouseService warehouseService;
+    @Autowired
+    private RcsBusTaskNoticeService rcsBusTaskNoticeService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -509,7 +512,7 @@
     }
 
     /**
-     * 鎵嬪姩瀹屾垚浠诲姟
+     * 鎵嬪姩瀹屾垚浠诲姟锛氬叆搴撶被缃� 98銆佸嚭搴撶被缃� 198锛屽簱浣�/鍗曟嵁鎵e噺涓庝笂鎶ョ敱瀵瑰簲瀹氭椂浠诲姟鎵ц
      *
      * @param id
      * @param loginUserId
@@ -549,13 +552,22 @@
         }
 
         modiftyTaskSort(task, loginUserId);
-        
-        // 濡傛灉浠诲姟鐘舵�佸凡缁忔槸AWAIT (196)锛屽啀娆$偣鍑诲畬缁撴椂锛岀洿鎺ュ畬鎴�
-        if (task.getTaskStatus().equals(TaskStsType.AWAIT.id)) {
-            // AWAIT鐘舵�佺殑浠诲姟鍐嶆瀹岀粨锛岀洿鎺ヨ缃负鍑哄簱瀹屾垚
+
+        // 鍏ュ簱锛�->98锛屽嚭搴擄細-> 198锛岀敱 complateOutStock 瀹氭椂浠诲姟 鏇存柊搴撳瓨
+        if (task.getTaskType() < 100) {
+            task.setTaskStatus(TaskStsType.COMPLETE_IN.id);
+            if (StringUtils.isNotBlank(task.getOrgSite())) {
+                BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
+                        .eq(BasStation::getStationName, task.getOrgSite()));
+                if (Objects.nonNull(station) && station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) {
+                    station.setUseStatus(LocStsType.LOC_STS_TYPE_O.type);
+                    if (!basStationService.updateById(station)) {
+                        throw new CoolException("鍏ュ簱绔欑偣鐘舵�佷慨鏀瑰け璐ワ紒锛�");
+                    }
+                }
+            }
+        } else {
             task.setTaskStatus(TaskStsType.COMPLETE_OUT.id);
-            
-            // 鏇存柊鍑哄簱绔欑偣鐘舵�侊紙涓嶳CS閫氱煡瀹岀粨淇濇寔涓�鑷达級
             if (task.getTaskType() >= TaskType.TASK_TYPE_OUT.type && StringUtils.isNotBlank(task.getTargSite())) {
                 BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
                         .eq(BasStation::getStationName, task.getTargSite()));
@@ -566,28 +578,17 @@
                     }
                 }
             }
-        } else {
-            // 鍏朵粬鎯呭喌鎸夊師鏈夐�昏緫澶勭悊
-            // 鍏ュ簱浠诲姟锛坱askType < 100锛夛細璁剧疆涓哄叆搴撳畬鎴�
-            // 鍑哄簱浠诲姟锛坱askType >= 100锛夛細璁剧疆涓虹瓑寰呯‘璁�
-            Integer newStatus = task.getTaskType() < 100 ? TaskStsType.COMPLETE_IN.id : TaskStsType.AWAIT.id;
-            task.setTaskStatus(newStatus);
-            
-            // 濡傛灉鏄叆搴撲换鍔″畬鎴愶紝鏇存柊鍏ュ簱绔欑偣鐘舵�侊紙涓嶳CS閫氱煡瀹岀粨淇濇寔涓�鑷达級
-            if (newStatus.equals(TaskStsType.COMPLETE_IN.id) && StringUtils.isNotBlank(task.getOrgSite())) {
-                BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>()
-                        .eq(BasStation::getStationName, task.getOrgSite()));
-                if (Objects.nonNull(station) && station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) {
-                    station.setUseStatus(LocStsType.LOC_STS_TYPE_O.type);
-                    if (!basStationService.updateById(station)) {
-                        throw new CoolException("鍏ュ簱绔欑偣鐘舵�佷慨鏀瑰け璐ワ紒锛�");
-                    }
-                }
-            }
         }
+        // 鍘燂細196 鏃跺啀鐐逛竴娆℃墠缃� 198锛涘嚭搴撻娆$偣鍑绘浘缃� 196(AWAIT)
+        // if (task.getTaskStatus().equals(TaskStsType.AWAIT.id)) { task.setTaskStatus(TaskStsType.COMPLETE_OUT.id); ... }
+        // else { Integer newStatus = task.getTaskType() < 100 ? COMPLETE_IN.id : AWAIT.id; ... }
         
         if (!this.updateById(task)) {
             throw new CoolException("瀹屾垚浠诲姟澶辫触");
+        }
+        // 绠$悊鍚庡彴銆屽畬鎴愪换鍔°�嶉�氱煡 RCS
+        if (StringUtils.isNotBlank(task.getTaskCode())) {
+            rcsBusTaskNoticeService.notifyTaskStatus(task.getTaskCode(), task.getTaskStatus());
         }
         return task;
     }
@@ -597,11 +598,12 @@
      *
      * @param id 浠诲姟ID
      * @param loginUserId 鐧诲綍鐢ㄦ埛ID
+     * @param notifyRcsFromAdmin 绠$悊鍚庡彴鍏ㄧ増鍑哄簱瀹岀粨鎺ュ彛涓� true 鏃堕�氱煡 RCS锛涘畾鏃�/PDA 绛変负 false
      * @return 浠诲姟瀵硅薄
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public Task completeFullOutStock(Long id, Long loginUserId) {
+    public Task completeFullOutStock(Long id, Long loginUserId, boolean notifyRcsFromAdmin) {
         // 鏌ヨ浠诲姟
         Task task = taskService.getOne(new LambdaQueryWrapper<Task>()
                 .eq(Task::getId, id));
@@ -667,6 +669,9 @@
 
         if (!this.updateById(task)) {
             throw new CoolException("浠诲姟鐘舵�佹洿鏂板け璐ワ紒锛�");
+        }
+        if (notifyRcsFromAdmin && StringUtils.isNotBlank(task.getTaskCode())) {
+            rcsBusTaskNoticeService.notifyTaskStatus(task.getTaskCode(), TaskStsType.UPDATED_OUT.id);
         }
 
         return task;
@@ -984,59 +989,56 @@
             }
         }
         
-        // 濡傛灉鏈変换鍔″凡涓嬪彂鍒癛CS锛屽厛璋冪敤RCS鍙栨秷鎺ュ彛
+        // 宸蹭笅鍙� RCS 鐨勫伐浣滄。锛氬繀椤诲厛璋� RCS 鍙栨秷鎺ュ彛鎴愬姛锛屽惁鍒欎笉鍏佽鍙栨秷宸ヤ綔妗�
         boolean rcsCancelSuccess = false;
         if (!rcsTaskCodes.isEmpty()) {
-            // 妫�鏌� RCS API 閰嶇疆鏄惁鏈夋晥
             if (rcsApi == null || StringUtils.isBlank(rcsApi.getHost()) || StringUtils.isBlank(rcsApi.getPort())) {
-                log.error("========== RCS浠诲姟鍙栨秷澶辫触 ==========");
-                log.error("RCS API 閰嶇疆鏃犳晥锛乭ost: {}, port: {}", 
-                        rcsApi != null ? rcsApi.getHost() : "null", 
-                        rcsApi != null ? rcsApi.getPort() : "null");
-                // 鍗充娇閰嶇疆鏃犳晥锛屼篃缁х画鎵ц浠诲姟鍒犻櫎鎿嶄綔
-            } else {
-                try {
-                    log.info("========== 寮�濮嬪彇娑圧CS浠诲姟 ==========");
-                    log.info("闇�瑕佸彇娑堢殑RCS浠诲姟缂栧彿锛歿}", rcsTaskCodes);
-                    String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.cancelTask;
-                    log.info("RCS鍙栨秷浠诲姟璇锋眰鍦板潃锛歿}", rcsUrl);
-                
-                // 濡傛灉娌℃湁鎵规缂栧彿锛屼娇鐢ㄧ涓�涓换鍔$紪鍙蜂綔涓烘壒娆$紪鍙�
-                if (StringUtils.isBlank(batchNo) && !rcsTaskCodes.isEmpty()) {
+                throw new CoolException("浠诲姟宸蹭笅鍙慠CS锛屼絾鏈厤缃甊CS鍦板潃锛屾棤娉曞彇娑堬紒锛�");
+            }
+            if (restTemplate == null) {
+                throw new CoolException("浠诲姟宸蹭笅鍙慠CS锛屼絾鏃犳硶璋冪敤RCS鍙栨秷鎺ュ彛锛屾棤娉曞彇娑堬紒锛�");
+            }
+            try {
+                log.info("========== 寮�濮嬪彇娑圧CS浠诲姟 ==========");
+                log.info("闇�瑕佸彇娑堢殑RCS浠诲姟缂栧彿锛歿}", rcsTaskCodes);
+                String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.cancelTask;
+                log.info("RCS鍙栨秷浠诲姟璇锋眰鍦板潃锛歿}", rcsUrl);
+
+                if (StringUtils.isBlank(batchNo)) {
                     batchNo = rcsTaskCodes.get(0);
                 }
-                
+
                 Map<String, Object> cancelParams = new HashMap<>();
                 cancelParams.put("tasks", rcsTaskCodes);
                 if (StringUtils.isNotBlank(batchNo)) {
                     cancelParams.put("batchNo", batchNo);
                 }
-                
+
                 log.info("RCS鍙栨秷浠诲姟璇锋眰鍙傛暟锛歿}", JSONObject.toJSONString(cancelParams));
-                
+
                 HttpHeaders headers = new HttpHeaders();
                 headers.add("Content-Type", "application/json");
                 headers.add("api-version", "v2.0");
                 HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(cancelParams, headers);
-                
+
                 long startTime = System.currentTimeMillis();
                 ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
                 long endTime = System.currentTimeMillis();
-                
+
                 log.info("RCS鍙栨秷浠诲姟鍝嶅簲鑰楁椂锛歿}ms", (endTime - startTime));
                 log.info("RCS鍙栨秷浠诲姟鍝嶅簲鐘舵�佺爜锛歿}", exchange.getStatusCode());
                 log.info("RCS鍙栨秷浠诲姟鍝嶅簲浣擄細{}", exchange.getBody());
-                
+
                 if (Objects.isNull(exchange.getBody())) {
                     log.error("RCS鍙栨秷浠诲姟澶辫触锛氬搷搴斾綋涓虹┖");
                     throw new CoolException("RCS鍙栨秷浠诲姟澶辫触锛氬搷搴斾綋涓虹┖");
                 }
-                
+
                 ObjectMapper objectMapper = new ObjectMapper();
                 objectMapper.coercionConfigDefaults()
                         .setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
                 CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
-                
+
                 if (result.getCode() == 200) {
                     log.info("========== RCS浠诲姟鍙栨秷鎴愬姛 ==========");
                     log.info("鎴愬姛鍙栨秷鐨凴CS浠诲姟缂栧彿锛歿}", rcsTaskCodes);
@@ -1045,22 +1047,28 @@
                     log.error("RCS鍙栨秷浠诲姟澶辫触锛歿}", result.getMsg());
                     throw new CoolException("RCS鍙栨秷浠诲姟澶辫触锛�" + result.getMsg());
                 }
-                } catch (JsonProcessingException e) {
-                    log.error("RCS鍙栨秷浠诲姟鍝嶅簲瑙f瀽澶辫触锛歿}", e.getMessage(), e);
-                    throw new CoolException("RCS鍙栨秷浠诲姟鍝嶅簲瑙f瀽澶辫触锛�" + e.getMessage());
-                } catch (Exception e) {
-                    log.error("RCS鍙栨秷浠诲姟寮傚父锛歿}", e.getMessage(), e);
-                    throw new CoolException("RCS鍙栨秷浠诲姟寮傚父锛�" + e.getMessage());
-                }
+            } catch (CoolException e) {
+                throw e;
+            } catch (JsonProcessingException e) {
+                log.error("RCS鍙栨秷浠诲姟鍝嶅簲瑙f瀽澶辫触锛歿}", e.getMessage(), e);
+                throw new CoolException("RCS鍙栨秷浠诲姟鍝嶅簲瑙f瀽澶辫触锛�" + e.getMessage());
+            } catch (Exception e) {
+                log.error("RCS鍙栨秷浠诲姟寮傚父锛歿}", e.getMessage(), e);
+                throw new CoolException("RCS鍙栨秷浠诲姟寮傚父锛�" + e.getMessage());
             }
         }
         
-        // 鏌ヨ绗﹀悎鍙栨秷鏉′欢鐨勪换鍔★紙鐘舵�佷负1銆�101銆�199锛�
-        List<Integer> allowedStatuses = Arrays.asList(TaskStsType.GENERATE_IN.id, TaskStsType.GENERATE_OUT.id, TaskStsType.WAVE_SEED.id);
+        // 鍙彇娑堢姸鎬侊細鍘� 1/101锛堜笉鍚� 199锛夛紱鎷f枡/鐩樼偣鍑哄簱 RCS 鎵ц涓�(<198)锛涙嫞鏂�/鐩樼偣鍐嶅叆搴�(53/57)涓嶆敮鎸佸彇娑�
         List<Task> tasks = this.list(new LambdaQueryWrapper<Task>()
                 .in(Task::getTaskType, list)
                 .in(Task::getId, (Object[]) ids)
-                .in(Task::getTaskStatus, allowedStatuses));
+                .and(w -> w
+                        .in(Task::getTaskStatus, Arrays.asList(
+                                TaskStsType.GENERATE_IN.id,
+                                TaskStsType.GENERATE_OUT.id))
+                        .or(w2 -> w2
+                                .in(Task::getTaskType, TaskType.TASK_TYPE_PICK_AGAIN_OUT.type, TaskType.TASK_TYPE_CHECK_OUT.type)
+                                .lt(Task::getTaskStatus, TaskStsType.COMPLETE_OUT.id))));
         
         // 濡傛灉绗﹀悎鍙栨秷鏉′欢鐨勪换鍔′负绌猴紝浣哛CS鍙栨秷鎴愬姛锛屽厑璁哥户缁紙鍙兘鏄换鍔$姸鎬佸凡鍙樻洿锛�
         if (tasks.isEmpty() && !rcsCancelSuccess) {

--
Gitblit v1.9.1