chen.lin
1 天以前 a2ef34a807b1f88ac9b18dae51adbf61ce821595
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
@@ -322,22 +322,47 @@
        // 2. 若未命中拣料/盘点入库,再校验组托并继续其他入库逻辑
        if (pickInTask == null && checkInTask == null) {
            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());
            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()));
        }
        // 检查其他入库任务类型(用箱号查询,状态为1或2)
        // 注意:盘点入库已单独处理,不再包含在此列表中
        // 检查该托盘号是否已有入库任务(含进行中、已完成),有则直接复用返回,拦截重复提交
        List<Integer> otherInboundTaskTypes = Arrays.asList(
                TaskType.TASK_TYPE_IN.type,
                TaskType.TASK_TYPE_MERGE_IN.type,
@@ -347,48 +372,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("组托档有任务编号,使用现有入库任务单号 - 任务编码:{},箱号:{},任务编号数量:{}",
                        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("组托档没有任务编号,继续创建新任务 - 箱号:{}", 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();
@@ -439,6 +451,14 @@
        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())) {
@@ -470,7 +490,7 @@
            waitPakin = mobileService.mergeItems(param, 1L);
        } catch (Exception e) {
            log.warn("[RCS入库申请-自动组托] 组托失败, barcode={}: {}", barcode, e.getMessage());
            return;
            throw new CoolException("barcode=" + barcode + ": " + e.getMessage());
        }
        String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_ASN_ORDER, null);
        if (StringUtils.isBlank(ruleCode)) {