From 98d88ac8caf7f0991d741079474c262f1e252927 Mon Sep 17 00:00:00 2001
From: chen.lin <1442464845@qq.com>
Date: 星期五, 06 三月 2026 08:14:54 +0800
Subject: [PATCH] 拣货过程中的出库库存匹配

---
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java |  451 +++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 331 insertions(+), 120 deletions(-)

diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
index f71d431..f1dd469 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
@@ -28,12 +28,18 @@
 import com.vincent.rsf.server.api.utils.SlaveProperties;
 import com.vincent.rsf.server.manager.entity.*;
 import com.vincent.rsf.server.manager.service.*;
+import com.vincent.rsf.server.manager.controller.params.PakinItem;
+import com.vincent.rsf.server.manager.controller.params.WaitPakinParam;
 import com.vincent.rsf.server.manager.service.impl.LocServiceImpl;
+import com.vincent.rsf.server.system.constant.GlobalConfigCode;
+import com.vincent.rsf.server.system.entity.Config;
+import com.vincent.rsf.server.system.service.ConfigService;
 import com.vincent.rsf.server.system.utils.SystemAuthUtils;
 import com.vincent.rsf.server.system.constant.SerialRuleCode;
 import com.vincent.rsf.server.manager.enums.LocStsType;
 import com.vincent.rsf.server.system.utils.SerialRuleUtils;
 import lombok.extern.slf4j.Slf4j;
+import lombok.val;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -47,6 +53,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Objects;
@@ -87,6 +94,16 @@
     private RestTemplate restTemplate;
     @Autowired
     private RemotesInfoProperties.RcsApi rcsApi;
+    @Autowired
+    private ConfigService configService;
+    @Autowired
+    private MatnrService matnrService;
+    @Autowired
+    private AsnOrderService asnOrderService;
+    @Autowired
+    private AsnOrderItemService asnOrderItemService;
+    @Autowired
+    private com.vincent.rsf.server.api.service.MobileService mobileService;
 
 
     @Override
@@ -124,75 +141,79 @@
         // 楠岃瘉璁惧绔欑偣
         DeviceSite deviceSite = validateDeviceSite(param);
 
-        // 鎻愬墠瀹氫箟waitPakin锛岄伩鍏嶄綔鐢ㄥ煙闂
+        // 鎻愬墠瀹氫箟 waitPakin / waitPakinItems锛屼緵鍚庣画鍏朵粬鍏ュ簱閫昏緫浣跨敤
         WaitPakin waitPakin = null;
+        List<WaitPakinItem> waitPakinItems = Collections.emptyList();
 
-        // 鍏堥獙璇佺粍鎷栫姸鎬侊紝鑾峰彇缁勬墭鏄庣粏淇℃伅锛堢敤浜庢壒鍙峰尮閰嶅拰鍗曞彿妫�鏌ワ級
-        waitPakin = validateWaitPakin(param.getBarcode());
-        List<WaitPakinItem> waitPakinItems = waitPakinItemService.list(
-                new LambdaQueryWrapper<WaitPakinItem>()
-                        .eq(WaitPakinItem::getPakinId, waitPakin.getId()));
-
-        // 鍏堟鏌ユ槸鍚︽湁鎷f枡鍏ュ簱浠诲姟锛堥渶瑕佸悓鏃跺尮閰嶇鍙峰拰鎵瑰彿锛�
+        // 1. 鍏堟煡璇换鍔$鐞嗕腑鐨勬嫞鏂欏叆搴撲换鍔°�佺洏鐐瑰叆搴撲换鍔★紙浠呮寜绠卞彿+绫诲瀷+鐘舵�侊紝涓嶄緷璧栫粍鎵橈級
         Task pickInTask = null;
-        // 妫�鏌ユ槸鍚︽湁鐩樼偣鍏ュ簱浠诲姟锛堥渶瑕佸悓鏃跺尮閰嶇鍙峰拰鎵瑰彿锛�
         Task checkInTask = null;
-
-        if (!waitPakinItems.isEmpty()) {
-            // 鑾峰彇缁勬墭鏄庣粏涓殑鎵瑰彿鍒楄〃锛堝幓閲嶏級
-            List<String> batchList = waitPakinItems.stream()
+        // 鍙�夛細鑻ユ湁缁勬墭鍒欏彇鎵瑰彿锛岀敤浜庡浠诲姟鏃朵紭鍏堟寜鎵瑰彿鍖归厤
+        WaitPakin waitPakinForBatch = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
+                .eq(WaitPakin::getBarcode, param.getBarcode())
+                .in(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val, PakinIOStatus.PAKIN_IO_STATUS_TASK_EXCE.val));
+        List<String> batchList = Collections.emptyList();
+        if (waitPakinForBatch != null) {
+            List<WaitPakinItem> itemsForBatch = waitPakinItemService.list(
+                    new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getPakinId, waitPakinForBatch.getId()));
+            batchList = itemsForBatch.stream()
                     .map(WaitPakinItem::getBatch)
                     .filter(Objects::nonNull)
                     .filter(batch -> !batch.trim().isEmpty())
                     .distinct()
                     .collect(Collectors.toList());
-
             if (!batchList.isEmpty()) {
-                log.info("妫�鏌ョ粍鎵樻槑缁嗘壒鍙� - 鎵瑰彿鍒楄〃锛歿}", batchList);
+                log.info("妫�鏌ョ粍鎵樻槑缁嗘壒鍙凤紙鐢ㄤ簬鍖归厤鎷f枡/鐩樼偣鍏ュ簱浠诲姟锛� - 鎵瑰彿鍒楄〃锛歿}", batchList);
+            }
+        }
 
-                // 鏌ヨ鎷f枡鍏ュ簱浠诲姟锛氱鍙峰尮閰嶄笖鐘舵�佷负1銆�2鎴�199锛圧CS鐢宠鍏ュ簱鏃讹紝鐘舵��199闇�瑕佸彉鎴�2锛�
-                List<Task> pickInTasks = taskService.list(new LambdaQueryWrapper<Task>()
-                        .eq(Task::getBarcode, param.getBarcode())
-                        .eq(Task::getTaskType, TaskType.TASK_TYPE_PICK_IN.type)
-                        .in(Task::getTaskStatus, TaskStsType.GENERATE_IN.id, TaskStsType.WAVE_SEED.id)
-                        .orderByDesc(Task::getCreateTime));
+        // 鏌ヨ浠诲姟绠$悊锛氭嫞鏂欏叆搴撲换鍔★紙绠卞彿+绫诲瀷53+鐘舵��1/2/199锛�
+        List<Task> pickInTasks = taskService.list(new LambdaQueryWrapper<Task>()
+                .eq(Task::getBarcode, param.getBarcode())
+                .eq(Task::getTaskType, TaskType.TASK_TYPE_PICK_IN.type)
+                .in(Task::getTaskStatus, TaskStsType.GENERATE_IN.id, TaskStsType.WCS_EXECUTE_IN.id, TaskStsType.WAVE_SEED.id)
+                .orderByDesc(Task::getCreateTime));
+        for (Task task : pickInTasks) {
+            if (batchList.isEmpty()) {
+                pickInTask = task;
+                log.info("鎵惧埌鍖归厤鐨勬嫞鏂欏叆搴撲换鍔★紙鎸夌鍙凤級 - 浠诲姟缂栫爜锛歿}锛岀鍙凤細{}", task.getTaskCode(), param.getBarcode());
+                break;
+            }
+            List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>()
+                    .eq(TaskItem::getTaskId, task.getId())
+                    .in(TaskItem::getBatch, batchList));
+            if (!taskItems.isEmpty()) {
+                pickInTask = task;
+                log.info("鎵惧埌鍖归厤鐨勬嫞鏂欏叆搴撲换鍔★紙绠卞彿鍜屾壒鍙烽兘鍖归厤锛� - 浠诲姟缂栫爜锛歿}锛屾壒鍙凤細{}", task.getTaskCode(), batchList);
+                break;
+            }
+        }
 
-                // 閫氳繃TaskItem鐨刡atch瀛楁鍖归厤鎵瑰彿
-                for (Task task : pickInTasks) {
-                    List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>()
-                            .eq(TaskItem::getTaskId, task.getId())
-                            .in(TaskItem::getBatch, batchList));
-
-                    if (!taskItems.isEmpty()) {
-                        pickInTask = task;
-                        log.info("鎵惧埌鍖归厤鐨勬嫞鏂欏叆搴撲换鍔★紙绠卞彿鍜屾壒鍙烽兘鍖归厤锛� - 浠诲姟缂栫爜锛歿}锛屾壒鍙凤細{}",
-                                task.getTaskCode(), batchList);
-                        break;
-                    }
+        // 鏌ヨ浠诲姟绠$悊锛氱洏鐐瑰叆搴撲换鍔★紙绠卞彿+绫诲瀷+鐘舵��1/2/199锛�
+        if (pickInTask == null) {
+            List<Task> checkInTasks = taskService.list(new LambdaQueryWrapper<Task>()
+                    .eq(Task::getBarcode, param.getBarcode())
+                    .eq(Task::getTaskType, TaskType.TASK_TYPE_CHECK_IN.type)
+                    .in(Task::getTaskStatus, TaskStsType.GENERATE_IN.id, TaskStsType.WCS_EXECUTE_IN.id, TaskStsType.WAVE_SEED.id)
+                    .orderByDesc(Task::getCreateTime));
+            for (Task task : checkInTasks) {
+                if (batchList.isEmpty()) {
+                    checkInTask = task;
+                    log.info("鎵惧埌鍖归厤鐨勭洏鐐瑰叆搴撲换鍔★紙鎸夌鍙凤級 - 浠诲姟缂栫爜锛歿}锛岀鍙凤細{}", task.getTaskCode(), param.getBarcode());
+                    break;
                 }
-
-                // 鏌ヨ鐩樼偣鍏ュ簱浠诲姟锛氱鍙峰尮閰嶄笖鐘舵�佷负1銆�2鎴�199锛圧CS鐢宠鍏ュ簱鏃讹紝鐘舵��199闇�瑕佸彉鎴�2锛�
-                List<Task> checkInTasks = taskService.list(new LambdaQueryWrapper<Task>()
-                        .eq(Task::getBarcode, param.getBarcode())
-                        .eq(Task::getTaskType, TaskType.TASK_TYPE_CHECK_IN.type)
-                        .in(Task::getTaskStatus, TaskStsType.GENERATE_IN.id, TaskStsType.WCS_EXECUTE_IN.id, TaskStsType.WAVE_SEED.id)
-                        .orderByDesc(Task::getCreateTime));
-
-                // 閫氳繃TaskItem鐨刡atch瀛楁鍖归厤鎵瑰彿
-                for (Task task : checkInTasks) {
-                    List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>()
-                            .eq(TaskItem::getTaskId, task.getId())
-                            .in(TaskItem::getBatch, batchList));
-
-                    if (!taskItems.isEmpty()) {
-                        checkInTask = task;
-                        log.info("鎵惧埌鍖归厤鐨勭洏鐐瑰叆搴撲换鍔★紙绠卞彿鍜屾壒鍙烽兘鍖归厤锛� - 浠诲姟缂栫爜锛歿}锛屾壒鍙凤細{}",
-                                task.getTaskCode(), batchList);
-                        break;
-                    }
+                List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>()
+                        .eq(TaskItem::getTaskId, task.getId())
+                        .in(TaskItem::getBatch, batchList));
+                if (!taskItems.isEmpty()) {
+                    checkInTask = task;
+                    log.info("鎵惧埌鍖归厤鐨勭洏鐐瑰叆搴撲换鍔★紙绠卞彿鍜屾壒鍙烽兘鍖归厤锛� - 浠诲姟缂栫爜锛歿}锛屾壒鍙凤細{}", task.getTaskCode(), batchList);
+                    break;
                 }
             }
         }
+
+
 
         // 濡傛灉鏄嫞鏂欏叆搴撲换鍔★紝鐩存帴杩斿洖锛屼笉鏍¢獙缁勬墭
         if (Objects.nonNull(pickInTask)) {
@@ -300,8 +321,49 @@
             return msgDto;
         }
 
-        // 妫�鏌ュ叾浠栧叆搴撲换鍔$被鍨嬶紙鐢ㄧ鍙锋煡璇紝鐘舵�佷负1鎴�2锛�
-        // 娉ㄦ剰锛氱洏鐐瑰叆搴撳凡鍗曠嫭澶勭悊锛屼笉鍐嶅寘鍚湪姝ゅ垪琛ㄤ腑
+        // 2. 鑻ユ湭鍛戒腑鎷f枡/鐩樼偣鍏ュ簱锛屽啀鏍¢獙缁勬墭骞剁户缁叾浠栧叆搴撻�昏緫
+        if (pickInTask == null && checkInTask == null) {
+            String barcode = param.getBarcode();
+            // 璇ユ墭鐩樺凡鍦ㄥ簱瀛樹腑锛屼笉鍙噸澶嶇敵璇峰叆搴�
+            List<Loc> inStock = locService.list(new LambdaQueryWrapper<Loc>().eq(Loc::getBarcode, barcode));
+            if (!inStock.isEmpty()) {
+                throw new CoolException("barcode=" + barcode + ": 璇ユ墭鐩樺凡鍦ㄥ簱锛屼笉鍙噸澶嶇敵璇峰叆搴�");
+            }
+            // 璇ユ墭鐩樺嚭搴撲腑鏈畬鎴愶紝涓嶅彲鐢宠鍏ュ簱
+            List<Integer> outboundTaskTypes = Arrays.asList(
+                    TaskType.TASK_TYPE_OUT.type,
+                    TaskType.TASK_TYPE_PICK_AGAIN_OUT.type,
+                    TaskType.TASK_TYPE_MERGE_OUT.type,
+                    TaskType.TASK_TYPE_CHECK_OUT.type,
+                    TaskType.TASK_TYPE_EMPITY_OUT.type
+            );
+            Task outboundTask = taskService.getOne(new LambdaQueryWrapper<Task>()
+                    .eq(Task::getBarcode, barcode)
+                    .in(Task::getTaskType, outboundTaskTypes)
+                    .lt(Task::getTaskStatus, TaskStsType.COMPLETE_OUT.id));
+            if (outboundTask != null) {
+                throw new CoolException("barcode=" + barcode + ": 璇ユ墭鐩樺嚭搴撲腑鏈畬鎴愶紝涓嶅彲鐢宠鍏ュ簱");
+            }
+
+            // 鎸� barcode 鍔犻攣锛岄伩鍏嶅悓涓� barcode 骞跺彂璇锋眰閲嶅鑷姩缁勬墭銆侀噸澶嶇敓鎴愬叆搴撳崟
+            String barcodeForLock = param.getBarcode();
+            synchronized ((barcodeForLock != null ? barcodeForLock : "").intern()) {
+                waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
+                        .eq(WaitPakin::getBarcode, param.getBarcode())
+                        .in(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val, PakinIOStatus.PAKIN_IO_STATUS_TASK_EXCE.val));
+                // 绌烘墭鐩樻棤缁勬墭鏃讹細鑻ラ厤缃惎鐢ㄥ垯鎸� AUTO_FULL_OUT_MATNR_CODE 鑷姩缁勬墭骞剁敓鎴愬叆搴撳崟锛屽啀缁х画鍏ュ簱浠诲姟閫昏緫
+                if (waitPakin == null) {
+                    tryAutoPakinForBarcode(param.getBarcode());
+                    waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
+                            .eq(WaitPakin::getBarcode, param.getBarcode())
+                            .in(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val, PakinIOStatus.PAKIN_IO_STATUS_TASK_EXCE.val));
+                }
+            }
+            waitPakin = validateWaitPakin(param.getBarcode());
+            waitPakinItems = waitPakinItemService.list(
+                    new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getPakinId, waitPakin.getId()));
+        }
+        // 妫�鏌ヨ鎵樼洏鍙锋槸鍚﹀凡鏈夊叆搴撲换鍔★紙鍚繘琛屼腑銆佸凡瀹屾垚锛夛紝鏈夊垯鐩存帴澶嶇敤杩斿洖锛屾嫤鎴噸澶嶆彁浜�
         List<Integer> otherInboundTaskTypes = Arrays.asList(
                 TaskType.TASK_TYPE_IN.type,
                 TaskType.TASK_TYPE_MERGE_IN.type,
@@ -311,48 +373,35 @@
         Task existingInTask = taskService.getOne(new LambdaQueryWrapper<Task>()
                 .eq(Task::getBarcode, param.getBarcode())
                 .in(Task::getTaskType, otherInboundTaskTypes)
-                .in(Task::getTaskStatus, TaskStsType.GENERATE_IN.id, TaskStsType.WCS_EXECUTE_IN.id)
                 .orderByDesc(Task::getCreateTime)
                 .last("LIMIT 1"));
 
         if (Objects.nonNull(existingInTask)) {
-            log.info("鎵惧埌鍖归厤鐨勫叾浠栧叆搴撲换鍔� - 浠诲姟缂栫爜锛歿}锛屼换鍔$被鍨嬶細{}锛岀鍙凤細{}",
-                    existingInTask.getTaskCode(), existingInTask.getTaskType(), param.getBarcode());
+            log.info("鎵惧埌璇ユ墭鐩樺彿宸叉湁鍏ュ簱浠诲姟锛屽鐢ㄥ苟鎷︽埅閲嶅鎻愪氦 - 浠诲姟缂栫爜锛歿}锛岀鍙凤細{}锛岀姸鎬侊細{}",
+                    existingInTask.getTaskCode(), param.getBarcode(), existingInTask.getTaskStatus());
 
-            // 妫�鏌ョ粍鎵樻槑缁嗘槸鍚︽湁璁㈠崟缂栫爜锛堜换鍔$紪鍙凤級
-            List<WaitPakinItem> itemsWithAsnCode = waitPakinItems.stream()
-                    .filter(item -> StringUtils.isNotBlank(item.getAsnCode()))
-                    .collect(Collectors.toList());
-
-            if (!itemsWithAsnCode.isEmpty()) {
-                log.info("缁勬墭妗f湁浠诲姟缂栧彿锛屼娇鐢ㄧ幇鏈夊叆搴撲换鍔″崟鍙� - 浠诲姟缂栫爜锛歿}锛岀鍙凤細{}锛屼换鍔$紪鍙锋暟閲忥細{}",
-                        existingInTask.getTaskCode(), param.getBarcode(), itemsWithAsnCode.size());
-
-                // 鏇存柊鍏ュ簱绔欑偣淇℃伅锛堝鏋滀笌褰撳墠鐢宠鐨勭珯鐐逛笉鍚岋級
-                if (StringUtils.isNotBlank(param.getSourceStaNo()) &&
-                        !param.getSourceStaNo().equals(existingInTask.getOrgSite())) {
-                    log.info("鏇存柊鍏ュ簱浠诲姟鐨勫叆搴撶珯鐐� - 浠诲姟缂栫爜锛歿}锛屽師绔欑偣锛歿}锛屾柊绔欑偣锛歿}",
-                            existingInTask.getTaskCode(), existingInTask.getOrgSite(), param.getSourceStaNo());
-                    existingInTask.setOrgSite(param.getSourceStaNo());
-                    if (!taskService.updateById(existingInTask)) {
-                        log.warn("鏇存柊鍏ュ簱浠诲姟鐨勫叆搴撶珯鐐瑰け璐� - 浠诲姟缂栫爜锛歿}", existingInTask.getTaskCode());
-                    }
+            // 鏇存柊鍏ュ簱绔欑偣淇℃伅锛堝鏋滀笌褰撳墠鐢宠鐨勭珯鐐逛笉鍚岋級
+            if (StringUtils.isNotBlank(param.getSourceStaNo()) &&
+                    !param.getSourceStaNo().equals(existingInTask.getOrgSite())) {
+                log.info("鏇存柊鍏ュ簱浠诲姟鐨勫叆搴撶珯鐐� - 浠诲姟缂栫爜锛歿}锛屽師绔欑偣锛歿}锛屾柊绔欑偣锛歿}",
+                        existingInTask.getTaskCode(), existingInTask.getOrgSite(), param.getSourceStaNo());
+                existingInTask.setOrgSite(param.getSourceStaNo());
+                if (!taskService.updateById(existingInTask)) {
+                    log.warn("鏇存柊鍏ュ簱浠诲姟鐨勫叆搴撶珯鐐瑰け璐� - 浠诲姟缂栫爜锛歿}", existingInTask.getTaskCode());
                 }
-
-                // 杩斿洖鐜版湁鍏ュ簱浠诲姟鐨勪俊鎭�
-                InTaskMsgDto msgDto = new InTaskMsgDto();
-                msgDto.setWorkNo(existingInTask.getTaskCode());
-                msgDto.setTaskId(existingInTask.getId());
-                msgDto.setLocNo(existingInTask.getTargLoc());
-                msgDto.setSourceStaNo(existingInTask.getOrgSite());
-                msgDto.setStaNo(existingInTask.getTargSite());
-                return msgDto;
-            } else {
-                log.info("缁勬墭妗f病鏈変换鍔$紪鍙凤紝缁х画鍒涘缓鏂颁换鍔� - 绠卞彿锛歿}", param.getBarcode());
             }
-        } else {
-            log.info("鏈壘鍒板尮閰嶇殑鍏朵粬鍏ュ簱浠诲姟锛岀户缁垱寤烘柊浠诲姟 - 绠卞彿锛歿}", param.getBarcode());
+
+            // 鐩存帴杩斿洖宸叉湁浠诲姟淇℃伅锛屼笉鍐嶆柊寤轰换鍔�
+            InTaskMsgDto msgDto = new InTaskMsgDto();
+            msgDto.setWorkNo(existingInTask.getTaskCode());
+            msgDto.setTaskId(existingInTask.getId());
+            msgDto.setLocNo(existingInTask.getTargLoc());
+            msgDto.setSourceStaNo(existingInTask.getOrgSite());
+            msgDto.setStaNo(existingInTask.getTargSite());
+            return msgDto;
         }
+
+        log.info("鏈壘鍒拌鎵樼洏鍙峰凡鏈夊叆搴撲换鍔★紝缁х画鍒涘缓鏂颁换鍔� - 绠卞彿锛歿}", param.getBarcode());
 
         // 鐢熸垚浠诲姟缂栫爜
         String ruleCode = generateTaskCode();
@@ -365,6 +414,9 @@
             throw new RuntimeException(e);
         }
 
+        if (waitPakin == null) {
+            throw new CoolException("璇锋鏌ョ粍鎷栫姸鎬佹槸鍚﹀畬鎴愶紒锛�");
+        }
         // 鍒涘缓骞朵繚瀛樹换鍔�
         Task task = createTask(ruleCode, locNo.getLocNo(), waitPakin.getBarcode(),
                 deviceSite.getDeviceSite(), param.getSourceStaNo().toString(), param.getUser());
@@ -389,6 +441,103 @@
 
 
     /**
+     * RCS 鍏ュ簱鐢宠鏃惰嫢 barcode 鏃犵粍鎵樹笖閰嶇疆鍚敤锛氭寜 AUTO_FULL_OUT_MATNR_CODE 鏃犺鍗曠粍鎵樺苟鐢熸垚鍏ュ簱鍗曪紝渚夸簬鍚庣画鐢熸垚鍏ュ簱浠诲姟銆�
+     */
+    private void tryAutoPakinForBarcode(String barcode) {
+        Config enabledConfig = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.AUTO_PAKIN_ON_ASN_ENABLED));
+        if (enabledConfig == null || !Boolean.parseBoolean(enabledConfig.getVal())) {
+            return;
+        }
+        Config matnrConfig = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.AUTO_FULL_OUT_MATNR_CODE));
+        if (matnrConfig == null || StringUtils.isBlank(matnrConfig.getVal())) {
+            return;
+        }
+        // 浜屾纭锛氬凡鏈夎 barcode 鐨勭粍鎵樺垯鐩存帴杩斿洖锛岀敱澶栧眰澶嶇敤锛岄伩鍏嶉噸澶嶈姹傜敓鎴愬鏉″叆搴撳崟
+        WaitPakin existing = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
+                .eq(WaitPakin::getBarcode, barcode)
+                .in(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val, PakinIOStatus.PAKIN_IO_STATUS_TASK_EXCE.val));
+        if (existing != null) {
+            log.info("[RCS鍏ュ簱鐢宠-鑷姩缁勬墭] barcode={} 宸叉湁缁勬墭锛岃烦杩囪嚜鍔ㄧ粍鎵�", barcode);
+            return;
+        }
+        Config qtyConfig = configService.getOne(new LambdaQueryWrapper<Config>().eq(Config::getFlag, GlobalConfigCode.AUTO_PAKIN_QTY));
+        double autoQty = 1.0;
+        if (qtyConfig != null && StringUtils.isNotBlank(qtyConfig.getVal())) {
+            try {
+                autoQty = Double.parseDouble(qtyConfig.getVal().trim());
+                if (autoQty <= 0) autoQty = 1.0;
+            } catch (NumberFormatException e) {
+                // ignore
+            }
+        }
+        String matnrCode = matnrConfig.getVal().trim();
+        Matnr matnr = matnrService.getOne(new LambdaQueryWrapper<Matnr>().eq(Matnr::getCode, matnrCode));
+        if (matnr == null) {
+            log.warn("[RCS鍏ュ簱鐢宠-鑷姩缁勬墭] 鐗╂枡涓嶅瓨鍦�: {}", matnrCode);
+            return;
+        }
+        List<PakinItem> pakinItems = new ArrayList<>();
+        PakinItem pi = new PakinItem();
+        pi.setMatnrId(matnr.getId());
+        pi.setReceiptQty(autoQty);
+        pi.setAsnCode(null);
+        pi.setId(null);
+        pakinItems.add(pi);
+        WaitPakinParam param = new WaitPakinParam();
+        param.setBarcode(barcode);
+        param.setItems(pakinItems);
+        WaitPakin waitPakin;
+        try {
+            waitPakin = mobileService.mergeItems(param, 1L);
+        } catch (Exception e) {
+            log.warn("[RCS鍏ュ簱鐢宠-鑷姩缁勬墭] 缁勬墭澶辫触, barcode={}: {}", barcode, e.getMessage());
+            throw new CoolException("barcode=" + barcode + ": " + e.getMessage());
+        }
+        String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_ASN_ORDER, null);
+        if (StringUtils.isBlank(ruleCode)) {
+            log.warn("[RCS鍏ュ簱鐢宠-鑷姩缁勬墭] 鍏ュ簱鍗曠紪鐮佽鍒欐湭閰嶇疆");
+            return;
+        }
+//        val orderWorkTypeOtherIn = OrderWorkType.ORDER_WORK_TYPE_OTHER_IN.type;
+        //                .setWkType(orderWorkTypeOtherIn)
+        WkOrder order = new WkOrder();
+        order.setCode(ruleCode)
+                .setType(OrderType.ORDER_IN.type)
+                .setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val)
+                .setAnfme(autoQty)
+                .setWorkQty(0.0)
+                .setQty(0.0)
+                .setCreateBy(1L)
+                .setUpdateBy(1L);
+        if (!asnOrderService.save(order)) {
+            throw new CoolException("鍏ュ簱涓诲崟淇濆瓨澶辫触");
+        }
+        WkOrderItem orderItem = new WkOrderItem();
+        orderItem.setOrderId(order.getId())
+                .setOrderCode(order.getCode())
+                .setMatnrId(matnr.getId())
+                .setMatnrCode(matnr.getCode())
+                .setMaktx(matnr.getName())
+                .setAnfme(autoQty)
+                .setWorkQty(0.0)
+                .setQty(0.0)
+                .setStockUnit(matnr.getStockUnit() != null ? matnr.getStockUnit() : "涓�")
+                .setPurUnit(matnr.getPurUnit() != null ? matnr.getPurUnit() : "涓�")
+                .setFieldsIndex(matnr.getFieldsIndex())
+                .setCreateBy(1L)
+                .setUpdateBy(1L);
+        if (!asnOrderItemService.save(orderItem)) {
+            throw new CoolException("鍏ュ簱鏄庣粏淇濆瓨澶辫触");
+        }
+        waitPakinItemService.update(new LambdaUpdateWrapper<WaitPakinItem>()
+                .eq(WaitPakinItem::getPakinId, waitPakin.getId())
+                .set(WaitPakinItem::getAsnId, order.getId())
+                .set(WaitPakinItem::getAsnCode, order.getCode())
+                .set(WaitPakinItem::getAsnItemId, orderItem.getId()));
+        log.info("[RCS鍏ュ簱鐢宠-鑷姩缁勬墭] 宸茬粍鎵樺苟鐢熸垚鍏ュ簱鍗�: {}, barcode: {}, 鐗╂枡: {}, 鏁伴噺: {}", order.getCode(), barcode, matnrCode, autoQty);
+    }
+
+    /**
      * 楠岃瘉璁惧绔欑偣
      */
     private DeviceSite validateDeviceSite(TaskInParam param) {
@@ -408,7 +557,7 @@
     private WaitPakin validateWaitPakin(String barcode) {
         WaitPakin waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>()
                 .eq(WaitPakin::getBarcode, barcode)
-                .in(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val, PakinIOStatus.PAKIN_IO_STATUS_TASK_EXCE.val));
+                    .in(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val, PakinIOStatus.PAKIN_IO_STATUS_TASK_EXCE.val));
 
         if (Cools.isEmpty(waitPakin)) {
             throw new CoolException("璇锋鏌ョ粍鎷栫姸鎬佹槸鍚﹀畬鎴愶紒锛�");
@@ -432,10 +581,18 @@
      */
     private Task createTask(String ruleCode, String targetLoc, String barcode,
                             String targetSite, String sourceSiteNo, Long loginUserId) {
+        return createTask(ruleCode, targetLoc, barcode, targetSite, sourceSiteNo, loginUserId, TaskType.TASK_TYPE_IN.type);
+    }
+
+    /**
+     * 鍒涘缓骞朵繚瀛樹换鍔★紙鏀寔鎸囧畾浠诲姟绫诲瀷锛屽绌烘澘鍏ュ簱锛�
+     */
+    private Task createTask(String ruleCode, String targetLoc, String barcode,
+                            String targetSite, String sourceSiteNo, Long loginUserId, Integer taskType) {
         Task task = new Task();
         task.setTaskCode(ruleCode)
                 .setTaskStatus(TaskStsType.GENERATE_IN.id)
-                .setTaskType(TaskType.TASK_TYPE_IN.type)
+                .setTaskType(taskType != null ? taskType : TaskType.TASK_TYPE_IN.type)
                 .setWarehType(WarehType.WAREHOUSE_TYPE_CRN.val)
                 .setTargLoc(targetLoc)
                 .setBarcode(barcode)
@@ -461,6 +618,75 @@
         if (!updated) {
             throw new CoolException("搴撲綅棰勭害澶辫触锛侊紒");
         }
+    }
+
+    /**
+     * 绌烘澘鍏ュ簱锛歊CS 鐢宠鏃� full=true锛屾棤闇�缁勬墭锛屽垎閰嶅簱浣嶅苟鍒涘缓 TASK_TYPE_EMPITY_IN 浠诲姟銆�
+     * 闇�鍦ㄨ澶囩珯鐐逛腑閰嶇疆 type=10锛堢┖鏉垮叆搴擄級鐨勭珯鐐硅矾寰勩��
+     */
+    private InTaskMsgDto createInTaskForEmptyPallet(String barcode, String staNo, Integer type) {
+        TaskInParam param = new TaskInParam();
+        param.setBarcode(barcode);
+        param.setSourceStaNo(staNo);
+        param.setLocType1(type != null ? type : 1);
+        param.setIoType(TaskType.TASK_TYPE_EMPITY_IN.type);
+        param.setUser(1L);
+
+        // 鏍¢獙璁惧绔欑偣锛堥渶閰嶇疆 type=10 绌烘澘鍏ュ簱鐨勭珯鐐癸級
+        DeviceSite deviceSite = validateDeviceSite(param);
+
+        // 妫�鏌ヨ鎵樼洏鍙锋槸鍚﹀凡鏈夌┖鏉垮叆搴撲换鍔★紝鏈夊垯澶嶇敤
+        Task existingInTask = taskService.getOne(new LambdaQueryWrapper<Task>()
+                .eq(Task::getBarcode, barcode)
+                .eq(Task::getTaskType, TaskType.TASK_TYPE_EMPITY_IN.type)
+                .orderByDesc(Task::getCreateTime)
+                .last("LIMIT 1"));
+        if (existingInTask != null) {
+            log.info("鎵惧埌璇ユ墭鐩樺彿宸叉湁绌烘澘鍏ュ簱浠诲姟锛屽鐢� - 浠诲姟缂栫爜锛歿}锛岀鍙凤細{}", existingInTask.getTaskCode(), barcode);
+            if (StringUtils.isNotBlank(staNo) && !staNo.equals(existingInTask.getOrgSite())) {
+                existingInTask.setOrgSite(staNo);
+                taskService.updateById(existingInTask);
+            }
+            InTaskMsgDto msgDto = new InTaskMsgDto();
+            msgDto.setWorkNo(existingInTask.getTaskCode());
+            msgDto.setTaskId(existingInTask.getId());
+            msgDto.setLocNo(existingInTask.getTargLoc());
+            msgDto.setSourceStaNo(existingInTask.getOrgSite());
+            msgDto.setStaNo(existingInTask.getTargSite());
+            return msgDto;
+        }
+
+        // 璇ユ墭鐩樺凡鍦ㄥ簱鎴栧嚭搴撲腑锛屼笉鍙噸澶嶇敵璇风┖鏉垮叆搴�
+        List<Loc> inStock = locService.list(new LambdaQueryWrapper<Loc>().eq(Loc::getBarcode, barcode));
+        if (!inStock.isEmpty()) {
+            throw new CoolException("barcode=" + barcode + ": 璇ユ墭鐩樺凡鍦ㄥ簱锛屼笉鍙噸澶嶇敵璇峰叆搴�");
+        }
+        Task outboundTask = taskService.getOne(new LambdaQueryWrapper<Task>()
+                .eq(Task::getBarcode, barcode)
+                .in(Task::getTaskType, Arrays.asList(TaskType.TASK_TYPE_OUT.type, TaskType.TASK_TYPE_EMPITY_OUT.type,
+                        TaskType.TASK_TYPE_PICK_AGAIN_OUT.type, TaskType.TASK_TYPE_CHECK_OUT.type))
+                .lt(Task::getTaskStatus, TaskStsType.COMPLETE_OUT.id));
+        if (outboundTask != null) {
+            throw new CoolException("barcode=" + barcode + ": 璇ユ墭鐩樺嚭搴撲腑鏈畬鎴愶紝涓嶅彲鐢宠鍏ュ簱");
+        }
+
+        InTaskMsgDto locNo;
+        try {
+            locNo = getLocNo(param);
+        } catch (Exception e) {
+            throw new CoolException("鑾峰彇绌烘澘鍏ュ簱搴撲綅澶辫触锛�" + e.getMessage());
+        }
+        if (locNo == null || StringUtils.isBlank(locNo.getLocNo())) {
+            throw new CoolException("鏈壘鍒板彲鐢ㄧ殑绌哄簱浣嶏紝璇锋鏌ュ簱鍖轰笌璁惧绔欑偣閰嶇疆锛堢┖鏉垮叆搴撻渶閰嶇疆 type=10 鐨勭珯鐐癸級");
+        }
+        String ruleCode = generateTaskCode();
+        String targetSite = StringUtils.isNotBlank(deviceSite.getDeviceSite()) ? deviceSite.getDeviceSite() : staNo;
+        Task task = createTask(ruleCode, locNo.getLocNo(), barcode, targetSite, staNo, param.getUser(), TaskType.TASK_TYPE_EMPITY_IN.type);
+        updateLocStatus(task.getTargLoc(), barcode);
+        locNo.setWorkNo(ruleCode);
+        locNo.setTaskId(task.getId());
+        log.info("[绌烘澘鍏ュ簱] 宸插垱寤轰换鍔�: {}, 搴撲綅: {}, 鏂欑: {}", ruleCode, locNo.getLocNo(), barcode);
+        return locNo;
     }
 
     /**
@@ -867,6 +1093,7 @@
                         throw new CoolException("浠诲姟鐘舵�佷慨鏀瑰け璐ワ紒锛佸綋鍓嶄换鍔$姸鎬侊細" + task.getTaskStatus() + "锛岀洰鏍囩姸鎬侊細" + TaskStsType.COMPLETE_IN.id);
                     }
                     log.info("鍏ュ簱浠诲姟鐘舵�佹洿鏂版垚鍔� - 浠诲姟缂栫爜锛歿}", task.getTaskCode());
+                    // 鍏ュ簱瀹屾暣闂幆鐢卞畾鏃朵换鍔″畬鎴愶細TaskSchedules.completeInStock 鎵弿 COMPLETE_IN锛屾墽琛屽簱浣�/缁勬墭/涓婃姤浜戜粨
                 }
             } else if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)
                     || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)
@@ -909,33 +1136,7 @@
                         throw new CoolException("浠诲姟鐘舵�佷慨鏀瑰け璐ワ紒锛佸綋鍓嶄换鍔$姸鎬侊細" + task.getTaskStatus() + "锛岀洰鏍囩姸鎬侊細" + TaskStsType.COMPLETE_OUT.id);
                     }
                     log.info("鍑哄簱浠诲姟鐘舵�佹洿鏂版垚鍔� - 浠诲姟缂栫爜锛歿}", task.getTaskCode());
-
-                    // 鍏ㄧ増鍑哄簱鍦≧CS鍥炶皟鍚庡鐞嗗簱瀛樺苟璁剧疆涓�199锛岀瓑寰匬DA蹇�熸嫞璐х‘璁ゅ悗鏇存柊涓�200
-                    if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) {
-                        log.info("鍏ㄧ増鍑哄簱浠诲姟锛屽紑濮嬪鐞嗗簱瀛樺苟鏇存柊鐘舵�佷负199 - 浠诲姟缂栫爜锛歿}", task.getTaskCode());
-                        try {
-                            // 閲嶆柊鏌ヨ浠诲姟浠ヨ幏鍙栨渶鏂扮姸鎬侊紙198锛�
-                            task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode()));
-
-                            // 璋冪敤completeTask澶勭悊搴撳瓨锛堜細璁剧疆涓�199锛�
-                            List<Task> taskList = new ArrayList<>();
-                            taskList.add(task);
-                            taskService.completeTask(taskList);
-
-                            // 閲嶆柊鏌ヨ浠诲姟浠ヨ幏鍙栨渶鏂扮姸鎬侊紙199锛�
-                            task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode()));
-
-                            if (task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)) {
-                                log.info("鍏ㄧ増鍑哄簱浠诲姟鐘舵�佸凡鏇存柊涓�199锛堢瓑寰匬DA蹇�熸嫞璐х‘璁ゅ悗鏇存柊涓�200锛� - 浠诲姟缂栫爜锛歿}", task.getTaskCode());
-                            } else {
-                                log.warn("鍏ㄧ増鍑哄簱浠诲姟鐘舵�佹洿鏂颁负199澶辫触 - 浠诲姟缂栫爜锛歿}锛屽綋鍓嶇姸鎬侊細{}",
-                                        task.getTaskCode(), task.getTaskStatus());
-                            }
-                        } catch (Exception e) {
-                            log.error("鍏ㄧ増鍑哄簱浠诲姟澶勭悊澶辫触 - 浠诲姟缂栫爜锛歿}锛岄敊璇細{}", task.getTaskCode(), e.getMessage(), e);
-                            // 涓嶆姏鍑哄紓甯革紝閬垮厤褰卞搷RCS鍥炶皟鐨勬甯歌繑鍥�
-                        }
-                    }
+                    // 鍑哄簱瀹屾暣闂幆锛堝簱瀛樸�佸嚭搴撳崟銆�9.1 涓婃姤浜戜粨锛夌敱瀹氭椂浠诲姟 TaskSchedules.complateOutStock 缁熶竴鎵ц
                 }
             }
         } else {
@@ -1355,9 +1556,19 @@
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public R allocateLocation(String barcode, String staNo, Integer type) {
+    public R allocateLocation(String barcode, String staNo, Integer type, Boolean full) {
         log.info("========== 寮�濮嬬敵璇峰叆搴撲换鍔★紝鍒嗛厤搴撲綅 ==========");
-        log.info("鏂欑鐮侊細{}锛屽叆搴撶珯鐐癸細{}锛屽叆搴撶被鍨嬶細{}", barcode, staNo, type);
+        log.info("鏂欑鐮侊細{}锛屽叆搴撶珯鐐癸細{}锛屽叆搴撶被鍨嬶細{}锛岀┖鏉匡細{}", barcode, staNo, type, full);
+
+        // full=true 鏃惰蛋绌烘澘鍏ュ簱锛堟棤闇�缁勬墭锛夛紱鍚﹀垯璧版櫘閫氬叆搴擄紙闇�缁勬墭鎴栬嚜鍔ㄧ粍鎵橈級
+        if (Boolean.TRUE.equals(full)) {
+            InTaskMsgDto msgDto = createInTaskForEmptyPallet(barcode, staNo, type);
+            JSONObject result = new JSONObject();
+            result.put("locNo", msgDto.getLocNo());
+            result.put("batchNo", msgDto.getWorkNo());
+            result.put("taskNo", msgDto.getWorkNo());
+            return R.ok(result);
+        }
 
         // 鏋勫缓 TaskInParam 鍙傛暟锛屼笌 /wcs/create/in/task 鎺ュ彛鍙傛暟涓�鑷�
         TaskInParam param = new TaskInParam();

--
Gitblit v1.9.1