chen.lin
6 天以前 cb249acbd7ed7f3bc2afa2bc9bee7d69ac8b5e30
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/WcsServiceImpl.java
@@ -39,6 +39,7 @@
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;
@@ -139,6 +140,11 @@
        // 验证设备站点
        DeviceSite deviceSite = validateDeviceSite(param);
        // 空板入库:与非空板同一入口,仅不校验组托,只做分配库位、建任务、更新库位
        if (param.getIoType() != null && param.getIoType().equals(TaskType.TASK_TYPE_EMPITY_IN.type)) {
            return createInTaskForEmptyPallet(param.getBarcode(), param.getSourceStaNo(), param.getLocType1());
        }
        // 提前定义 waitPakin / waitPakinItems,供后续其他入库逻辑使用
        WaitPakin waitPakin = null;
@@ -497,6 +503,8 @@
            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)
@@ -578,10 +586,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)
@@ -607,6 +623,75 @@
        if (!updated) {
            throw new CoolException("库位预约失败!!");
        }
    }
    /**
     * 空板入库:与非空板同一流程(校验站点、分配库位、建任务、更新库位),仅不校验组托、不写任务明细、不更新组托状态。
     * 由 createInTask 在 ioType=空板时调用;需在设备站点中配置 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;
    }
    /**
@@ -1476,30 +1561,18 @@
     */
    @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);
        // 构建 TaskInParam 参数,与 /wcs/create/in/task 接口参数一致
        // 统一走 createInTask:空板(full=true)仅不校验组托,仍校验站点、分配库位、建任务;非空板需组托
        TaskInParam param = new TaskInParam();
        param.setBarcode(barcode);
        param.setSourceStaNo(staNo);
        param.setIoType(TaskType.TASK_TYPE_IN.type); // 入库类型
        param.setLocType1(type); // 库位类型(高低检测信号)
        param.setUser(1L); // 默认用户ID,可以根据实际需求调整
        param.setLocType1(type != null ? type : 1);
        param.setUser(1L);
        param.setIoType(Boolean.TRUE.equals(full) ? TaskType.TASK_TYPE_EMPITY_IN.type : TaskType.TASK_TYPE_IN.type);
        // 调用 createInTask 方法,创建完整的入库任务
        // 该方法会执行以下流程:
        // 1. 验证设备站点
        // 2. 验证组拖状态
        // 3. 检查是否有匹配的入库任务(拣料/盘点入库会匹配状态199并更新为2)
        // 4. 生成任务编码(如果需要创建新任务)
        // 5. 获取库位号
        // 6. 创建并保存任务(如果需要创建新任务)
        // 7. 更新库位状态
        // 8. 获取并验证组拖明细
        // 9. 创建并保存任务明细
        // 10. 更新组托状态
        InTaskMsgDto msgDto = createInTask(param);
        // 查询任务当前状态