skyouc
2025-01-15 cc6dae7468506691bfb23ca81be5e14045771bce
#
拍灯容器流动流程修改
发货确认功能开发
部分功能优化
14个文件已修改
2个文件已添加
641 ■■■■ 已修改文件
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/controller/OutStockController.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/controller/WaveManagentController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/entity/domain/SystemProperties.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/entity/request/SlapLightControlParam.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/services/Impl/WcsApiServiceImpl.java 288 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/services/WcsApiService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/controller/MobileController.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/entity/dto/ShippingOrderDetlDto.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/mapper/WaveSeedMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/service/MobileService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/service/impl/CacheSiteServiceImpl.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/service/impl/MobileServiceImpl.java 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/service/impl/WorkServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/timer/TaskTimer.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/timer/TaskWaveTimer.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/resources/mapper/asrs/WaveSeedMapper.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/controller/OutStockController.java
@@ -2,7 +2,9 @@
import com.zy.asrs.framework.common.R;
import com.zy.asrs.framework.exception.CoolException;
import com.zy.asrs.wms.apis.wcs.entity.request.ContainerArrivedParam;
import com.zy.asrs.wms.apis.wcs.entity.request.RfidSingalRequest;
import com.zy.asrs.wms.apis.wcs.entity.request.TasksStatusCallbackParam;
import com.zy.asrs.wms.apis.wcs.services.WcsApiService;
import com.zy.asrs.wms.system.controller.BaseController;
@@ -10,6 +12,9 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.Objects;
@Slf4j
@RestController
@@ -61,7 +66,10 @@
    }
    /**
     * 容器流动通知
     * 容器流动通知(当前物料播种完成)
     * //fixme 此接口将不再单独调用
     * 1. 更新当前任务物料信息
     * 2.
     * @param code 容器编码
     * @return
     */
@@ -70,9 +78,54 @@
        if (StringUtil.isNullOrEmpty(code)) {
            return R.error("容器编码不能为空!!!");
        }
        return wcsApiService.containerConveryor(code);
    }
    /**
     * 发送命令给电子标签,可以控制电子标签亮灯颜色及灭灯等。
     *
     * 1. 判断当前容器是否还有物料未拣,未拣完闪灯,拣完通知容器流动,并灭灯
     * 2. 容器流动判断,如果料箱没有物料 code传200, 有物料传100 执行回库任务, IOTYP = 4
     *
     * @param request
     * @return
     */
    @PostMapping("/slap/light")
    public R slapLightLogic(@RequestBody Map<String, Object> request) {
        if (Objects.isNull(request)) {
            throw new CoolException("参数不能为空!!");
        }
        if (Objects.isNull(request.get("taskNo"))) {
            throw new CoolException("任务号不能为空!!");
        }
        if (Objects.isNull(request.get("orderNO"))){
            throw new CoolException("当前任务订单号不能为空!!");
        }
         wcsApiService.slapLightLogic(request);
        return R.ok();
    }
    /**
     * 信号回传接口,回传电子标签状态变化内容给上游系统。
     * 当人为操作(比如拍灯,更改数字,放箱等)导致电子标签的状态和信号等发生变化、或设备本身发生异常时,ESS接收到信号后,通过该接口将信号回传给上游系统。
     *
     * RFID回调接口
     *
     * @param request
     * @return
     */
    public R rfidCallback(@RequestBody RfidSingalRequest request) {
        if (Objects.isNull(request)) {
            throw new CoolException("参数不能为空!!");
        }
        return wcsApiService.rfidCallback(request);
    }
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/controller/WaveManagentController.java
@@ -135,17 +135,6 @@
    }
    /**
     * 信号回传接口,回传电子标签状态变化内容给上游系统。
     * 当人为操作(比如拍灯,更改数字,放箱等)导致电子标签的状态和信号等发生变化、或设备本身发生异常时,ESS接收到信号后,通过该接口将信号回传给上游系统。
     * @param request
     * @return
     */
    @PostMapping("/")
    public R rfidCallback(@RequestBody RfidSingalRequest request) {
        return R.ok();
    }
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/entity/domain/SystemProperties.java
@@ -1,6 +1,7 @@
package com.zy.asrs.wms.apis.wcs.entity.domain;
import com.zy.asrs.wms.system.entity.Host;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@@ -21,5 +22,7 @@
    public static String CONVEYOR_START = HOST + "/conveyor/moveContainer";
    public static String SLAP_LIGHT = HOST + "/expand/api/equipment/ptl/sendCommand";
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/entity/request/SlapLightControlParam.java
New file
@@ -0,0 +1,47 @@
package com.zy.asrs.wms.apis.wcs.entity.request;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class SlapLightControlParam implements Serializable {
    /**
     * 控制器code,需要与控制器配置ptlController里的code对应。
     */
    private String controllerCode;
    /**
     * 电子标签序号,需要与电子标签ptlTag里的index对应。
     */
    private String index;
    /**
     * 电子标签编号,需要与电子标签ptlTag里的code对应
     */
    private String tagCode;
    /**
     * 颜色:
     * RED
     * GREEN
     * BLUE
     */
    private String color;
    /**
     * 工作模式:
     * LIGHT:亮灯
     * DARK:灭灯
     * FLASH:闪灯
     */
    private String mode;
    /**
     * 常用于显示数字,支持3位数。
     */
    private String display;
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/services/Impl/WcsApiServiceImpl.java
@@ -1,25 +1,37 @@
package com.zy.asrs.wms.apis.wcs.services.Impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zy.asrs.framework.common.R;
import com.zy.asrs.framework.exception.CoolException;
import com.zy.asrs.wms.apis.wcs.entity.domain.SystemProperties;
import com.zy.asrs.wms.apis.wcs.entity.enums.EssTaskStatus;
import com.zy.asrs.wms.apis.wcs.entity.request.*;
import com.zy.asrs.wms.apis.wcs.entity.response.CommonReponse;
import com.zy.asrs.wms.apis.wcs.services.WcsApiService;
import com.zy.asrs.wms.asrs.entity.Task;
import com.zy.asrs.wms.asrs.entity.TaskDetl;
import com.zy.asrs.wms.asrs.entity.WaveSeed;
import com.zy.asrs.wms.asrs.entity.enums.TaskStsType;
import com.zy.asrs.wms.asrs.service.TaskService;
import com.zy.asrs.wms.asrs.service.WaitPakinService;
import com.zy.asrs.wms.asrs.service.WorkService;
import com.zy.asrs.wms.asrs.service.*;
import io.jsonwebtoken.lang.Collections;
import lombok.extern.slf4j.Slf4j;
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.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j
@Service
@@ -31,7 +43,14 @@
    private WorkService workService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private TaskDetlService taskDetlService;
    @Autowired
    private WaveSeedService waveSeedService;
    @Autowired
    private RestTemplate restTemplate;
    /**
@@ -78,6 +97,13 @@
        return R.success("success");
    }
    /**
     * 容器执行状态上报
     *
     * @param callbackParam
     * @param stockType
     * @param hostId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receiveTaskStatus(TasksStatusCallbackParam callbackParam, String stockType, Long hostId) {
@@ -86,87 +112,89 @@
                .eq(Task::getTaskNo, callbackParam.getTaskCode()));
        if (!Collections.isEmpty(list)) {
            list.forEach(task -> {
                    TaskStsType taskStsType = null;
                    if (stockType.equals("inStock")) { //入库任务
                        if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_TOTE_LOAD.event)) { //上报取箱状态
                            if (task.getTaskSts() == TaskStsType.WCS_CONVEYOR_START.id) {
                                taskStsType = TaskStsType.WCS_TOTE_LOAD;
                            } else {
                                String errMsg = "任务编号:" + task.getTaskNo() +  "状态为不匹配,"  + "不能执行:" + TaskStsType.WCS_TOTE_LOAD.desc + "任务";
                                log.error(errMsg);
                                throw new CoolException(errMsg);
                            }
                        } else if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_TOTE_UNLOAD.event)) { //上报放箱状态
                            if (task.getTaskSts() == TaskStsType.WCS_TOTE_LOAD.id) {
                                taskStsType = TaskStsType.WCS_TOTE_UNLOAD;
                            } else {
                                String errMsg = "任务编号:" + task.getTaskNo() +  "状态为不匹配,"  + "不能执行:" + TaskStsType.WCS_TOTE_UNLOAD.desc + "任务";
                                log.error(errMsg);
                                throw new CoolException(errMsg);
                            }
                        } else if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_STATUS.event)) { //TODO 需确认上报任务中,任务完成是哪个事件,目前暂定task事件
                            if (task.getTaskSts() == TaskStsType.WCS_TOTE_UNLOAD.id) {
                                taskStsType = TaskStsType.WCS_PUTAWAY_SUCESS;
                            } else {
                                String errMsg = "任务编号:" + task.getTaskNo() +  "状态为不匹配,"  + "不能执行:" + TaskStsType.WCS_PUTAWAY_SUCESS.desc + "任务";
                                log.error(errMsg);
                                throw new CoolException(errMsg);
                            }
                TaskStsType taskStsType = null;
                if (stockType.equals("inStock")) { //入库任务
                    if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_TOTE_LOAD.event)) { //上报取箱状态
                        if (task.getTaskSts() == TaskStsType.WCS_CONVEYOR_START.id) {
                            taskStsType = TaskStsType.WCS_TOTE_LOAD;
                        } else {
                            String errMsg = "任务编号:" + task.getTaskNo() + "状态为不匹配," + "不能执行:" + TaskStsType.WCS_TOTE_LOAD.desc + "任务";
                            log.error(errMsg);
                            throw new CoolException(errMsg);
                        }
                        boolean result = taskService.update(new LambdaUpdateWrapper<Task>()
                                .set(Task::getRobotCode, callbackParam.getRobotCode())
                                .set(Task::getSysTaskCode, callbackParam.getSysTaskCode())
                                .set(Task::getTaskSts, taskStsType.id)
                                .set(Task::getExcudeStatus, callbackParam.getStatus())
                                .set(Task::getTaskDesc, callbackParam.getMessage())
                                .eq(Task::getBarcode, callbackParam.getContainerCode())
                                .eq(Task::getTaskNo, callbackParam.getTaskCode()));
                        if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_STATUS.event) && result) {
                            workService.completeTask(task.getId());
                    } else if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_TOTE_UNLOAD.event)) { //上报放箱状态
                        if (task.getTaskSts() == TaskStsType.WCS_TOTE_LOAD.id) {
                            taskStsType = TaskStsType.WCS_TOTE_UNLOAD;
                        } else {
                            String errMsg = "任务编号:" + task.getTaskNo() + "状态为不匹配," + "不能执行:" + TaskStsType.WCS_TOTE_UNLOAD.desc + "任务";
                            log.error(errMsg);
                            throw new CoolException(errMsg);
                        }
                    } else { //出库任务
                        if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_TOTE_LOAD.event)) { //上报取箱状态
                            //TODO 定时器开启后,要删除 || task.getTaskType() == TaskStsType.GENERATE_OUT.id
                            if (task.getTaskSts() == TaskStsType.WCS_EXECUTE_OUT.id || task.getTaskSts() == TaskStsType.GENERATE_OUT.id) {
                                taskStsType = TaskStsType.WCS_EXECUTE_OUT_TOTE_LOAD;
                            } else {
                                String errMsg = "任务编号:" + task.getTaskNo() +  "状态为不匹配,"  + "不能执行:" + TaskStsType.WCS_EXECUTE_OUT_TOTE_LOAD.desc + "任务";
                                log.error(errMsg);
                                throw new CoolException(errMsg);
                            }
                        } else if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_TOTE_UNLOAD.event)) { //上报放箱状态
                            if (task.getTaskSts() == TaskStsType.WCS_EXECUTE_OUT_TOTE_LOAD.id) {
                                taskStsType = TaskStsType.WCS_EXECUTE_OUT_TOTE_UNLOAD;
                            } else {
                                String errMsg = "任务编号:" + task.getTaskNo() +  "状态为不匹配,"  + "不能执行:" + TaskStsType.WCS_EXECUTE_OUT_TOTE_UNLOAD.desc + "任务";
                                log.error(errMsg);
                                throw new CoolException(errMsg);
                            }
                        } else if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_STATUS.event)) { //上报完成状态
                            if (task.getTaskSts() == TaskStsType.WCS_EXECUTE_OUT_TOTE_UNLOAD.id || task.getTaskSts() == TaskStsType.WCS_EXECUTE_OUT_TASK_DONE.id) {
                                //出库任务完成,修改状态为容器到达,定时任务生成播种波次
                                taskStsType = TaskStsType.WCS_EXECUTE_OUT_TASK_DONE;
                            } else {
                                String errMsg = "任务编号:" + task.getTaskNo() +  "状态为不匹配,"  + "不能执行:" + TaskStsType.WCS_EXECUTE_OUT_TASK_DONE.desc + "任务";
                                log.error(errMsg);
                                throw new CoolException(errMsg);
                            }
                    } else if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_STATUS.event)) { //TODO 需确认上报任务中,任务完成是哪个事件,目前暂定task事件
                        if (task.getTaskSts() == TaskStsType.WCS_TOTE_UNLOAD.id) {
                            taskStsType = TaskStsType.WCS_PUTAWAY_SUCESS;
                        } else {
                            String errMsg = "任务编号:" + task.getTaskNo() + "状态为不匹配," + "不能执行:" + TaskStsType.WCS_PUTAWAY_SUCESS.desc + "任务";
                            log.error(errMsg);
                            throw new CoolException(errMsg);
                        }
                    }
                    boolean result = taskService.update(new LambdaUpdateWrapper<Task>()
                            .set(Task::getRobotCode, callbackParam.getRobotCode())
                            .set(Task::getSysTaskCode, callbackParam.getSysTaskCode())
                            .set(Task::getTaskSts, taskStsType.id)
                            .set(Task::getExcudeStatus, callbackParam.getStatus())
                            .set(Task::getTaskDesc, callbackParam.getMessage())
                            .eq(Task::getBarcode, callbackParam.getContainerCode())
                            .eq(Task::getTaskNo, callbackParam.getTaskCode()));
                        //更新出库状态及相关字段
                         taskService.update(new LambdaUpdateWrapper<Task>()
                                .set(Task::getRobotCode, callbackParam.getRobotCode())
                                .set(Task::getSysTaskCode, callbackParam.getSysTaskCode())
                                .set(Task::getTaskSts, taskStsType.id)
                                .set(Task::getExcudeStatus, callbackParam.getStatus())
                                .set(Task::getTaskDesc, callbackParam.getMessage())
                                .eq(Task::getBarcode, callbackParam.getContainerCode())
                                .eq(Task::getTaskNo, callbackParam.getTaskCode()));
                    //event事件为task,表明任务上报完成状态
                    if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_STATUS.event) && result) {
                        //任务状态修改为 99 入库完成
                        workService.completeTask(task.getId());
                    }
                } else { //出库任务
                    if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_TOTE_LOAD.event)) { //上报取箱状态
                        //TODO 定时器开启后,要删除 || task.getTaskType() == TaskStsType.GENERATE_OUT.id
                        if (task.getTaskSts() == TaskStsType.WCS_EXECUTE_OUT.id || task.getTaskSts() == TaskStsType.GENERATE_OUT.id) {
                            taskStsType = TaskStsType.WCS_EXECUTE_OUT_TOTE_LOAD;
                        } else {
                            String errMsg = "任务编号:" + task.getTaskNo() + "状态为不匹配," + "不能执行:" + TaskStsType.WCS_EXECUTE_OUT_TOTE_LOAD.desc + "任务";
                            log.error(errMsg);
                            throw new CoolException(errMsg);
                        }
                    } else if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_TOTE_UNLOAD.event)) { //上报放箱状态
                        if (task.getTaskSts() == TaskStsType.WCS_EXECUTE_OUT_TOTE_LOAD.id) {
                            taskStsType = TaskStsType.WCS_EXECUTE_OUT_TOTE_UNLOAD;
                        } else {
                            String errMsg = "任务编号:" + task.getTaskNo() + "状态为不匹配," + "不能执行:" + TaskStsType.WCS_EXECUTE_OUT_TOTE_UNLOAD.desc + "任务";
                            log.error(errMsg);
                            throw new CoolException(errMsg);
                        }
                    } else if (callbackParam.getEventType().equals(EssTaskStatus.TASK_EVENT_STATUS.event)) { //上报完成状态
                        if (task.getTaskSts() == TaskStsType.WCS_EXECUTE_OUT_TOTE_UNLOAD.id || task.getTaskSts() == TaskStsType.WCS_EXECUTE_OUT_TASK_DONE.id) {
                            //出库任务完成,修改状态为容器到达,定时任务生成播种波次
                            taskStsType = TaskStsType.WCS_EXECUTE_OUT_TASK_DONE;
                        } else {
                            String errMsg = "任务编号:" + task.getTaskNo() + "状态为不匹配," + "不能执行:" + TaskStsType.WCS_EXECUTE_OUT_TASK_DONE.desc + "任务";
                            log.error(errMsg);
                            throw new CoolException(errMsg);
                        }
                    }
                });
                    //更新出库状态及相关字段
                    taskService.update(new LambdaUpdateWrapper<Task>()
                            .set(Task::getRobotCode, callbackParam.getRobotCode())
                            .set(Task::getSysTaskCode, callbackParam.getSysTaskCode())
                            .set(Task::getTaskSts, taskStsType.id)
                            .set(Task::getExcudeStatus, callbackParam.getStatus())
                            .set(Task::getTaskDesc, callbackParam.getMessage())
                            .eq(Task::getBarcode, callbackParam.getContainerCode())
                            .eq(Task::getTaskNo, callbackParam.getTaskCode()));
                }
            });
        } else {
            throw new CoolException("更新内容不存在!!");
        }
@@ -174,15 +202,16 @@
    /**
     * 容器流动通知
     *
     * @param code
     * @return
     */
    @Override
    public R containerConveryor(String code) {
    public synchronized R containerConveryor(String code) {
        List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, code));
        if (tasks.isEmpty()) {
            return R.error("容器码任务不存在!!");
        } else if (tasks.size() > 1){
        } else if (tasks.size() > 1) {
            return R.error("容器码任务错误!!");
        }
        tasks.forEach(task -> {
@@ -214,6 +243,8 @@
            //流动通知下发完成后,修改任务状态为输送线流动中。。
            //TODO 判断任务是否为103拣料出库,103拣料流动后修改为4(RCS容器流动任务已下发)
            if (task.getTaskType() == 103) {
                //TODO 需找海柔确认是否需要重新调用入库接口
                //更新库存信息,修改任务状态为4 (RCS容器流动任务已下发)
                workService.pickTask(task.getId());
//                taskService.update(new LambdaUpdateWrapper<Task>().eq(Task::getId, task.getId()).set(Task::getTaskSts, TaskStsType.WCS_CONVEYOR_START))
            } else {
@@ -238,4 +269,99 @@
        return R.ok();
    }
    @Override
    public R rfidCallback(RfidSingalRequest request) {
        return null;
    }
    /**
     * 拍灯拣料逻辑,详细说明见接口调用说明
     *
     * @param request
     */
    @Override
    public void slapLightLogic(Map<String, Object> request) {
        String taskNo = request.get("taskNo").toString();
        String orderNo = request.get("orderNo").toString();
        //* 1. 判断当前容器是否还有物料未拣,未拣完闪灯,拣完通知容器流动,并灭灯
        SlapLightControlParam slapParam = new SlapLightControlParam();
        MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
        //默认流动
        boolean converyor = false;
        //判断是否还有物料未拣
        if (!checked(orderNo, taskNo)) {
            //调用三方接口,闪灯不做操作
            // 设置请求参数
            params.add("params", JSONObject.toJSONString(slapParam));
            log.info("请求地址:{},请求参数:{}", SystemProperties.SLAP_LIGHT, JSONObject.toJSONString(slapParam));
        } else {
            //调用三方接口,来灯通知容器流动, 传灭灯参数
            params.add("params", JSONObject.toJSONString(slapParam));
            log.info("请求地址:{},请求参数:{}", SystemProperties.SLAP_LIGHT, JSONObject.toJSONString(slapParam));
        }
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Type", "application/json");
        HttpEntity httpEntity = new HttpEntity<>(params, headers);
        // 请求
        ResponseEntity<CommonReponse> exchange = restTemplate.exchange(SystemProperties.CONVEYOR_START, HttpMethod.POST, httpEntity, CommonReponse.class);
        log.info("下发流动通知 返回结果:{}", exchange);
        if (exchange.getBody() == null) {
            throw new CoolException("下发流动通知失败!!");
        } else {
            CommonReponse response = exchange.getBody();
            if (response.getCode() == 0) {
                if (!converyor) {
                    //* 2. 容器流动判断,如果料箱没有物料 code传200, 有物料传100 执行回库任务,修改任务状态为  调用containerConveryor(taskNo)方法
                    containerConveryor(request.get("taskNo").toString());
                }
            }
        }
    }
    /**
     * 判断当前任务下,订单是否已完成拣货
     *
     * @param orderNo
     * @param taskNo
     * @return
     */
    public synchronized boolean checked(String orderNo, String taskNo) {
        if (Objects.isNull(orderNo)) {
            throw new CoolException("订单编码不能为空!!");
        }
        if (Objects.isNull(taskNo)) {
            throw new CoolException("任务编码不能为空!!");
        }
        List<TaskDetl> taskDetls = taskDetlService.list(new LambdaQueryWrapper<TaskDetl>().eq(TaskDetl::getTaskNo, taskNo));
        if (taskDetls.isEmpty()) {
            throw new CoolException("订单明细不存在!!");
        }
        List<Long> detlIds = taskDetls.stream().map(TaskDetl::getId).collect(Collectors.toList());
        double taskNum = taskDetls.stream().mapToDouble(TaskDetl::getAnfme).sum();
        List<WaveSeed> seeds = waveSeedService.list(new LambdaQueryWrapper<WaveSeed>().in(WaveSeed::getTaskDetlId, detlIds));
        if (seeds.isEmpty()) {
            throw new CoolException("播种信息不存在!!!");
        }
        double seedNum = seeds.stream().mapToDouble(WaveSeed::getWorkQty).sum();
        //判断任务需求总量是否等播种总数量
        if (taskNum == seedNum) {
            return true;
        } else  {
            return false;
        }
    }
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/apis/wcs/services/WcsApiService.java
@@ -2,7 +2,10 @@
import com.zy.asrs.framework.common.R;
import com.zy.asrs.wms.apis.wcs.entity.request.ContainerArrivedParam;
import com.zy.asrs.wms.apis.wcs.entity.request.RfidSingalRequest;
import com.zy.asrs.wms.apis.wcs.entity.request.TasksStatusCallbackParam;
import java.util.Map;
public interface WcsApiService {
@@ -11,4 +14,8 @@
    void receiveTaskStatus(TasksStatusCallbackParam callbackParam, String stockType, Long hostId);
    R containerConveryor(String code);
    void slapLightLogic(Map<String, Object> request);
    R rfidCallback(RfidSingalRequest request);
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/controller/MobileController.java
@@ -16,6 +16,7 @@
import com.zy.asrs.wms.asrs.entity.WaitPakin;
import com.zy.asrs.wms.asrs.entity.dto.OrderInfoDto;
import com.zy.asrs.wms.asrs.entity.dto.PickSheetDetlDto;
import com.zy.asrs.wms.asrs.entity.dto.ShippingOrderDetlDto;
import com.zy.asrs.wms.asrs.entity.param.BatchMergeOrdersParam;
import com.zy.asrs.wms.asrs.entity.param.PageRequest;
import com.zy.asrs.wms.asrs.entity.param.PakinOnShelvesParams;
@@ -258,4 +259,31 @@
        }
    }
    /**
     * 获取发货订单明细
     * @return
     */
    @PostMapping("/shipping/order/detl")
    public R  getOrderDetl(@RequestBody Map<String, Object> params) {
        if (Objects.isNull(params)) {
            throw new CoolException("参数不能为空!!");
        }
        return mobileService.selectShippingDetl(params);
    }
    /**
     * 确认发货单明细
     * @return
     */
    @PostMapping("/shipping/confirm")
    public R confirmShipping(@RequestBody List<ShippingOrderDetlDto> params) {
        if (params.isEmpty()) {
            throw new CoolException("发货单明细不能为空!!");
        }
        return mobileService.confirmShippingDetl(params);
    }
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/entity/dto/ShippingOrderDetlDto.java
New file
@@ -0,0 +1,42 @@
package com.zy.asrs.wms.asrs.entity.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class ShippingOrderDetlDto implements Serializable {
    /**
     * 订单编码
     */
    private String orderNo;
    /**
     * 订单明细标识
     */
    private String id;
    /**
     * 波次号
     */
    private String waveNo;
    /**
     * 订单需求量
     */
    private Double anfme;
    /**
     * 批次
     */
    private String batch;
    /**
     * 站点
     */
    private String siteNo;
    /**
     * 实际拣货量
     */
    private Double workQty;
    /**
     * 备注
     */
    private String memo;
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/mapper/WaveSeedMapper.java
@@ -6,6 +6,7 @@
import com.zy.asrs.wms.apis.wcs.entity.response.SowSeeds;
import com.zy.asrs.wms.asrs.entity.WaveSeed;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zy.asrs.wms.asrs.entity.dto.ShippingOrderDetlDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@@ -18,4 +19,5 @@
    List<SowSeeds> getSeedsList(@Param(Constants.WRAPPER) LambdaQueryWrapper<WaveSeed> ew);
    List<ShippingOrderDetlDto> selectShippingOrderDtel(@Param("orderNo") String orderNo);
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/service/MobileService.java
@@ -1,7 +1,9 @@
package com.zy.asrs.wms.asrs.service;
import com.zy.asrs.framework.common.R;
import com.zy.asrs.wms.asrs.entity.CacheSite;
import com.zy.asrs.wms.asrs.entity.dto.PickSheetDetlDto;
import com.zy.asrs.wms.asrs.entity.dto.ShippingOrderDetlDto;
import com.zy.asrs.wms.asrs.entity.param.BatchMergeOrdersParam;
import com.zy.asrs.wms.asrs.entity.param.PakinOnShelvesParams;
import com.zy.asrs.wms.system.entity.Host;
@@ -25,4 +27,8 @@
    List<CacheSite> getSeedLocs();
    boolean bindOrderBySite(Map<String, Object> param);
    R selectShippingDetl(Map<String, Object> params);
    R confirmShippingDetl(List<ShippingOrderDetlDto> params);
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/service/impl/CacheSiteServiceImpl.java
@@ -71,15 +71,7 @@
        List<WaveSeed> waveSeeds = waveSeedService.list(new LambdaQueryWrapper<WaveSeed>().eq(WaveSeed::getOrderId, orderId));
       //fixme 校验当前订单是否完成播种,需要获取当前波次所有任务中A物料的执行数量是否等于订单的总量-已完成数量(anfme - qty) 或者 任务中已执行数量是否等订单中的执行数量  workQty = workQty
        List<OrderDetl> orderDetls = orderDetlService.getOrderDetlByOrderId(orderId);
        //获取订单A所有明细物料
//        if (orderDetls.isEmpty()) {
//            throw new CoolException("订单明细不存在!!");
//        }
//        List<Long> matnrs = orderDetls.stream().map(OrderDetl::getMatId).collect(Collectors.toList());
//        orderDetls.forEach(orderDetl -> {
//
//        });
//        List<WaveSeed> waveSeeds = waveSeedService.list(new LambdaQueryWrapper<WaveSeed>().eq(WaveSeed::getWaveId, order.getWaveId()));
        for (WaveSeed waveSeed : waveSeeds) {
            Double anfme = stockMap.get(waveSeed.getOrderDetlId());
            if (anfme == null) {
@@ -89,7 +81,6 @@
            stockMap.put(waveSeed.getOrderDetlId(), anfme);
        }
//        List<OrderDetl> orderDetls = orderDetlService.getOrderDetlByOrderId(orderId);
        boolean check = true;
        for (OrderDetl orderDetl : orderDetls) {
            Double anfme = Optional.of(orderDetl.getAnfme() - orderDetl.getQty()).orElse(0.0D);
@@ -135,6 +126,7 @@
        Long waveId = order.getWaveId();
        boolean check = this.seedCompletePreview(param);
        if (!check) {//订单未处理完成
            List<Long> taskIds = new ArrayList<>();
            List<TaskDetl> taskDetls = taskDetlService.list(new LambdaQueryWrapper<TaskDetl>().eq(TaskDetl::getWaveId, waveId));
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/service/impl/MobileServiceImpl.java
@@ -2,18 +2,17 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zy.asrs.framework.common.R;
import com.zy.asrs.framework.exception.CoolException;
import com.zy.asrs.wms.asrs.entity.*;
import com.zy.asrs.wms.asrs.entity.dto.PickSheetDetlDto;
import com.zy.asrs.wms.asrs.entity.dto.ShippingOrderDetlDto;
import com.zy.asrs.wms.asrs.entity.enums.*;
import com.zy.asrs.wms.asrs.entity.enums.OrderType;
import com.zy.asrs.wms.asrs.entity.param.BatchMergeOrdersParam;
import com.zy.asrs.wms.asrs.entity.param.GeneratePakInParam;
import com.zy.asrs.wms.asrs.entity.param.PakinOnShelvesParams;
import com.zy.asrs.wms.asrs.mapper.CacheSiteMapper;
import com.zy.asrs.wms.asrs.mapper.OrderDetlLogMapper;
import com.zy.asrs.wms.asrs.mapper.OrderDetlMapper;
import com.zy.asrs.wms.asrs.mapper.SeedSitesMapper;
import com.zy.asrs.wms.asrs.mapper.*;
import com.zy.asrs.wms.asrs.service.*;
import com.zy.asrs.wms.system.entity.Host;
import com.zy.asrs.wms.system.service.HostService;
@@ -69,9 +68,13 @@
    private SeedSitesMapper seedSitesMapper;
    @Autowired
    private OrderDetlMapper orderDetlMapper;
    @Autowired
    private WaveSeedMapper waveSeedMapper;
    @Autowired
    private WaveSeedLogService waveSeedLogService;
    @Autowired
    private OrderDetlLogService orderDetlLogService;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -389,4 +392,94 @@
        return true;
    }
    @Override
    public R selectShippingDetl(Map<String, Object> params) {
        //判断订单是否为空
        if (StringUtil.isNullOrEmpty((String) params.get("orderNo"))) {
            throw new CoolException("订单编码号不能为空!!");
        }
        String orderId = params.get("orderNo").toString();
        List<ShippingOrderDetlDto> waveSeeds = waveSeedMapper.selectShippingOrderDtel(orderId);
        return R.ok(waveSeeds);
    }
    /**
     * 发货单明细确认
     * 1. 出库修改订单完成状态,判断订单是否完成,完成加入历史档,未完成修改订单已完成数量
     * 2. 删除订单已完成播种明细信息
     * 3. 清除集货区绑定数据
     * @param params
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R confirmShippingDetl(List<ShippingOrderDetlDto> params) {
        if (params.isEmpty()) {
            throw new CoolException("发货单据明细为空,不可执行发货操作!!");
        }
        params.forEach(order -> {
            //删除出库订单及明细,加入订单历史档
            if (order.getAnfme() == order.getWorkQty()) { //完全拣货
                OrderDetl byId = orderDetlService.getById(order.getId());
                OrderDetlLog orderDetlLog = new OrderDetlLog();
                BeanUtils.copyProperties(orderDetlLog, byId);
                orderDetlLog.setQty(order.getWorkQty());
                orderDetlLog.setWorkQty(0.0);
                if (!orderDetlLogService.save(orderDetlLog)) {
                    throw new CoolException("订单明细转历史档失败!!");
                }
                if (!orderDetlService.removeById(byId)) {
                    throw new CoolException("订单明细不存在!!");
                }
                //查询当前订单下否还有明细存在
                List<OrderDetl> orders = orderDetlService.list(new LambdaQueryWrapper<OrderDetl>().eq(OrderDetl::getOrderNo, order.getOrderNo()));
                if (orders.isEmpty()) {
                    Order one = orderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, order.getOrderNo()));
                    if (Objects.isNull(one)) {
                        throw new CoolException("订单不存在!!");
                    }
                    OrderLog orderLog = new OrderLog();
                    BeanUtils.copyProperties(one, orderLog);
                    if (!orderLogService.save(orderLog)) {
                        throw new CoolException("原始订单转历史档失败!!");
                    }
                    if (!orderService.remove(new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, order.getOrderNo()))) {
                        throw new CoolException("原始订单删除失败!!");
                    }
                }
            } else {
                //todo 删除已完成明细,保留原始主单及未完成明细
            }
            List<WaveSeed> waveSeeds = waveSeedMapper.selectList(new LambdaQueryWrapper<WaveSeed>().eq(WaveSeed::getOrderDetlId, order.getId()));
            //fixme 订单明细未播种,默认可发货
            if (!waveSeeds.isEmpty()) {
                ArrayList<WaveSeedLog> waveSeedLogs = new ArrayList<>();
                waveSeeds.forEach(seed -> {
                   WaveSeedLog waveSeedLog = new WaveSeedLog();
                   BeanUtils.copyProperties(waveSeedLog, seed);
                   waveSeedLog.setId(null);
                    waveSeedLogs.add(waveSeedLog);
               });
                if (waveSeedLogService.saveBatch(waveSeedLogs)) {
                    throw new CoolException("波明历史档保存失败!!");
                }
            }
            //删除播种明细信息
            if (waveSeedMapper.deleteByIds(waveSeeds) < 1) {
                throw new CoolException("播种明细删除携程!!");
            }
        });
        return null;
    }
}
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/service/impl/WorkServiceImpl.java
@@ -673,8 +673,9 @@
        }
        TaskDetl taskDetl = taskDetls.get(0);
        //生成库位
        //生成新的库位 !important
        Loc loc = this.generateLoc(taskType, taskDetl.getMatId(), taskDetl.getBatch(), taskDetl.getUniqueField(), locTypeHeightType.id);
        if(loc == null) {
            throw new CoolException("没有空库位");
        }
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/timer/TaskTimer.java
@@ -327,7 +327,6 @@
        Long hostId = task.getHostId();
        //fixme 将任务当前
        Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getLocNo, task.getTargetLoc()).eq(Loc::getHostId, hostId));
//        Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getLocNo, task.getTargetLoc()));
        if (loc == null) {
            throw new CoolException("库位不存在");
        }
@@ -339,6 +338,7 @@
        loc.setLocStsId(LocStsType.F.val());
        loc.setUpdateTime(new Date());
        loc.setBarcode(task.getBarcode());
        if (!locService.updateById(loc)) {
            throw new CoolException("库位状态更新失败");
        }
zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/timer/TaskWaveTimer.java
@@ -44,8 +44,8 @@
    /**
     * modifty:
     * original : fetch datasource of task type on WAVE_SEED
     * now: Fetch datasource of task type  on WCS_EXECUTE_OUT_ARRIVED, After completing the task and for setting  the task type equal to WAVE_SEED
     * original : fetch datasource of task type on WCS_EXECUTE_OUT_TASK_DONE
     * now: Fetch datasource of task type  on WCS_EXECUTE_OUT_ARRIVED, After completing the task and for setting  the task type equal to GENERATE_WAVE_SEED
     */
    @Scheduled(cron = "0/15 * * * * ? ")
    @Transactional(rollbackFor = Exception.class)
@@ -60,7 +60,7 @@
            if (!autoCreateWaveSeed.equals("true")) {
                return;
            }
            //查询状态为容器到达状态所有任务单据
            //查询状态为RCS任务完成所有任务单据
//            List<Task> taskList = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getTaskSts, TaskStsType.WAVE_SEED.id));
            List<Task> taskList = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getTaskSts, TaskStsType.WCS_EXECUTE_OUT_TASK_DONE.id));
            HashSet<String> sycMatnrs = new HashSet<>();
zy-asrs-wms/src/main/resources/mapper/asrs/WaveSeedMapper.xml
@@ -11,4 +11,28 @@
        ( SELECT id, site_id, site_no, order_no, anfme, work_qty, matnr, batch, create_time, `status`, create_by, memo, deleted FROM man_wave_seed ) t
        ${ew.customSqlSegment}
    </select>
    <select id="selectShippingOrderDtel" resultType="com.zy.asrs.wms.asrs.entity.dto.ShippingOrderDetlDto">
        SELECT
            mo.order_no,
            mo.id,
            wcs.wave_no,
            mo.anfme,
            mo.batch,
            wcs.site_no,
            wcs.work_qty,
            wcs.memo
        FROM
            man_order_detl mo
        LEFT JOIN
            (SELECT wave_no, order_detl_id , site_no, order_no, SUM(anfme) anfme, SUM(work_qty) work_qty, memo, batch, matnr
        FROM man_wave_seed GROUP BY order_id, matnr, batch) wcs
            ON mo.id = wcs.order_detl_id
        <where>
            1 = 1
            <if test="orderNo != null and orderNo != ''">
                AND mo.order_no = #{orderNo}
            </if>
        </where>
    </select>
</mapper>