自动化立体仓库 - WMS系统
src/main/java/com/zy/asrs/controller/OpenController.java
@@ -25,6 +25,7 @@
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
 * Created by vincent on 2022/4/8
@@ -50,12 +51,16 @@
    @Autowired
    private WrkDetlService wrkDetlService;
    @Autowired
    private WrkDetlLogService wrkDetlLogService;
    @Autowired
    private WrkMastService wrkMastService;
    @Autowired
    private WrkMastLogService wrkMastLogService;
    @Autowired
    private MatService matService;
    @Autowired
    private LocMastService locMastService;
    @Autowired
    private ReportQueryMapper reportQueryMapper;
//    @PostMapping("/order/matSync/default/v1")
@@ -123,6 +128,23 @@
        return R.ok().add(openService.pakinOrderComplete(param));
    }
    /**
     * 托盘入库历史记录重报ERP
     */
    @PostMapping("/order/pakin/erp/report/v1")
//    @AppAuth(memo = "入库历史重报ERP")
    public synchronized R reportPakinHistoryToErp(@RequestBody(required = false) List<String> barcodes) {
//        auth(appkey, barcodes, request);
        if (Cools.isEmpty(barcodes)) {
            return R.parse(BaseRes.PARAM);
        }
        try {
            return openService.reportPakinHistoryToErp(barcodes);
        } catch (Exception e) {
            return R.error(e.getMessage());
        }
    }
@@ -151,6 +173,7 @@
    private void auth(String appkey, Object obj, HttpServletRequest request) {
        log.info("{}接口被访问;appkey:{};请求数据:{}", "open/sensorType/list/auth/v1", appkey, JSON.toJSONString(obj));
        log.info("[auth] cache: {}", obj == null ? "null" : JSON.toJSONString(obj));
        request.setAttribute("cache", obj);
        if (!auth) {
            return;
@@ -396,8 +419,12 @@
    @PostMapping("/order/matSync/default/v2")
//    @AppAuth(memo = "商品信息同步接口")
    public synchronized R syncMatInfoV2(@RequestBody(required = false) List<MatSyncParam.MatParam> param){
    public synchronized R syncMatInfoV2(@RequestBody(required = false) List<MatSyncParam.MatParam> param,
                                        HttpServletRequest request) {
        if (request != null) {
            log.info("[syncMatInfoV2] cache: {}", param == null ? "null" : JSON.toJSONString(param));
            request.setAttribute("cache", param);
        }
        System.out.println(param);
        if (Cools.isEmpty(param)) {
            return R.parse(BaseRes.PARAM);
@@ -422,16 +449,24 @@
     * return
     */
    @PostMapping("/station/all")
    public synchronized R stationAll(){
    public synchronized R stationAll(HttpServletRequest request) {
        if (request != null) {
            String cachePayload = JSON.toJSONString(Collections.singletonMap("op", "stationAll"));
            log.info("[stationAll] cache: {}", cachePayload);
            request.setAttribute("cache", cachePayload);
        }
        return openService.stationAll();
    }
    /**
     * 组托信息下发
     * return
     * 7.3 组托信息下发
     */
    @PostMapping("/comb/auth")
    public synchronized R comb(@RequestBody ArrayList<MesToCombParam> param){
    public synchronized R comb(@RequestBody ArrayList<MesToCombParam> param, HttpServletRequest request) {
        if (request != null) {
            log.info("[comb] cache: {}", param == null ? "null" : JSON.toJSONString(param));
            request.setAttribute("cache", param);
        }
        List<MesToCombParam> errorComb = Lists.newArrayList();
        List<MesToCombParam> validComb = Lists.newArrayList();
        for (MesToCombParam mesToCombParam : param) {
@@ -459,6 +494,7 @@
            validComb.add(mesToCombParam);
        }
        for (MesToCombParam mesToCombParam : validComb) {
            mesToCombParam.setBoxType1("ERP");
            openService.mesToComb(mesToCombParam);
        }
        // TODO:待测试
@@ -470,21 +506,73 @@
    }
    /**
     * 出库通知单
     * 7.11 出库通知单(传递有序无序规则)
     */
    @PostMapping("/outOrder")
    public synchronized R outOrder (@RequestBody ArrayList<OutTaskParam> params){
    public synchronized R outOrder(@RequestBody ArrayList<OutTaskParam> params, HttpServletRequest request) {
        if (Cools.isEmpty(params)) {
            return R.error("请求参数不能为空");
        }
        Set<String> orderIds = new LinkedHashSet<>();
        log.info("[outOrder] cache: {}", JSON.toJSONString(params));
        request.setAttribute("cache", params);
        Map<String, List<OutTaskParam>> linesByBatch = new LinkedHashMap<>();
        for (OutTaskParam outTaskParam : params) {
            if (Cools.isEmpty(outTaskParam) || Cools.isEmpty(outTaskParam.getOrderId())) {
                return R.error("出库单号不能为空");
            }
            orderIds.add(outTaskParam.getOrderId());
            if (Cools.isEmpty(outTaskParam.getBatchSeq())) {
                outTaskParam.setBatchSeq(outTaskParam.getOrderId());
            }
            if (Cools.isEmpty(outTaskParam.getStationId())) {
                return R.error("托盘「" + outTaskParam.getPalletId() + "」出库口编码不能为空");
            }
            linesByBatch.computeIfAbsent(outTaskParam.getBatchSeq(), k -> new ArrayList<>()).add(outTaskParam);
        }
        for (Map.Entry<String, List<OutTaskParam>> entry : linesByBatch.entrySet()) {
            List<OutTaskParam> lines = entry.getValue();
            OutTaskParam head = lines.get(0);
            String oid = head.getOrderId();
            String batchSeq = head.getBatchSeq();
            boolean hasZero = false;
            boolean hasPositive = false;
            List<Integer> orderedSeqs = new ArrayList<>(lines.size());
            for (OutTaskParam line : lines) {
                if (line.getSeq() == null) {
                    return R.error("出库单「" + oid + "」批次「" + batchSeq + "」序号不能为空");
                }
                if (line.getSeq() < 0) {
                    return R.error("出库单「" + oid + "」批次「" + batchSeq + "」序号不能小于0");
                }
                if (line.getSeq() == 0) {
                    hasZero = true;
                } else {
                    hasPositive = true;
                    orderedSeqs.add(line.getSeq());
                }
            }
            if (hasZero && hasPositive) {
                return R.error("出库单「" + oid + "」批次「" + batchSeq + "」序号不能混用无序和有序");
            }
            if (!hasZero) {
                Collections.sort(orderedSeqs);
                for (int i = 0; i < orderedSeqs.size(); i++) {
                    if (!Objects.equals(orderedSeqs.get(i), i + 1)) {
                        return R.error("出库单「" + oid + "」批次「" + batchSeq + "」序号不连贯");
                    }
                }
            }
        }
        Set<String> seenPallet = new LinkedHashSet<>();
        for (OutTaskParam outTaskParam : params) {
            String pid = outTaskParam.getPalletId();
            String palletKey = pid == null ? "" : pid;
            if (!seenPallet.add(palletKey)) {
                return R.error("托盘号重复:" + (Cools.isEmpty(pid) ? "(空)" : pid));
            }
        }
//        if (!orderIds.isEmpty()) {
//            Set<String> existedOrderIds = new LinkedHashSet<>();
//            List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().in("user_no", orderIds));
@@ -504,41 +592,86 @@
//            }
//        }
        List<OutTaskParam> errorOutOrders = Lists.newArrayList();
        List<OutTaskParam> validOutOrders = Lists.newArrayList();
        List<OutTaskParam> missingStock = Lists.newArrayList();
        List<OutTaskParam> missingLoc = Lists.newArrayList();
        for (OutTaskParam outTaskParam : params) {
            // TODO:待測試,校驗庫存信息,不存在則返回
            int countLoc = locDetlService.selectCount(new EntityWrapper<LocDetl>().eq("zpallet", outTaskParam.getPalletId()));
            if (countLoc == 0){
                errorOutOrders.add(outTaskParam);
            if (countLoc == 0) {
                missingStock.add(outTaskParam);
                continue;
            }
            validOutOrders.add(outTaskParam);
        }
        for (OutTaskParam outTaskParam : validOutOrders) {
            R r = openService.outOrder(outTaskParam,validOutOrders.size());
            if (!r.get("code").equals(200)){
                return r;
            LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>().eq("loc_sts", "F").eq("barcode", outTaskParam.getPalletId()));
            if (locMast == null) {
                missingLoc.add(outTaskParam);
            }
        }
        if(errorOutOrders.size() > 0) {
            return R.error("库存中不存在该托盘").add(errorOutOrders);
        if (!missingStock.isEmpty()) {
            List<String> missingPalletIds = new ArrayList<>(missingStock.size());
            for (OutTaskParam p : missingStock) {
                String pid = p.getPalletId();
                missingPalletIds.add(Cools.isEmpty(pid) ? "(空)" : pid);
            }
            return R.error("库存中不存在该托盘:" + String.join(",", missingPalletIds)).add(missingStock);
        }
        if (!missingLoc.isEmpty()) {
            List<String> badPalletIds = new ArrayList<>(missingLoc.size());
            for (OutTaskParam p : missingLoc) {
                String pid = p.getPalletId();
                badPalletIds.add(Cools.isEmpty(pid) ? "(空)" : pid);
            }
            return R.error("没有找到托盘码对应库位:" + String.join(",", badPalletIds)).add(missingLoc);
        }
        return R.ok();
        return openService.outOrderBatch(params);
    }
    /**
     * 7.9 出库异常变动上报
     */
    @PostMapping("/order/pakout/abnormal/report/v1")
    public synchronized R outOrderAbnormalReport(@RequestBody OutOrderAbnormalReportParam param, HttpServletRequest request) {
        if (request != null) {
            log.info("[outOrderAbnormalReport] cache: {}", param == null ? "null" : JSON.toJSONString(param));
            request.setAttribute("cache", param);
        }
        if (Cools.isEmpty(param) || Cools.isEmpty(param.getPalletId())) {
            return R.error("palletId不能为空");
        }
        return openService.outOrderAbnormalReport(param);
    }
    /**
     * 7.10 出库异常变动处理
     */
    @PostMapping("/order/pakout/abnormal/handle/v1")
    public synchronized R outOrderAbnormalHandle(@RequestBody OutOrderAbnormalHandleParam param, HttpServletRequest request) {
        if (request != null) {
            log.info("[outOrderAbnormalHandle] cache: {}", param == null ? "null" : JSON.toJSONString(param));
            request.setAttribute("cache", param);
        }
        if (Cools.isEmpty(param) || Cools.isEmpty(param.getPalletId())) {
            return R.error("palletId不能为空");
        }
        return openService.outOrderAbnormalHandle(param);
    }
    /**
     * pause out order
     */
    @PostMapping("/order/pakout/pause/default/v1")
    public synchronized R pakoutOrderPause(@RequestBody OpenOrderPakoutPauseParam param){
    public synchronized R pakoutOrderPause(@RequestBody OpenOrderPakoutPauseParam param, HttpServletRequest request) {
        if (request != null) {
            log.info("[pakoutOrderPause] cache: {}", param == null ? "null" : JSON.toJSONString(param));
            request.setAttribute("cache", param);
        }
        if (Cools.isEmpty(param) || Cools.isEmpty(param.getOrderId())) {
            return R.error("orderNo is empty");
        }
        return openService.pakoutOrderPause(param);
    }
    private String buildOutOrderBatchKey(OutTaskParam param) {
        return param.getOrderId() + "#" + param.getBatchSeq();
    }
@@ -589,17 +722,77 @@
                }
            }
            AxisBean inqty = new AxisBean();
            inqty.setName("入库数量");
            inqty.setName("入库托盘数");
            Integer[] array1 = new Integer[data1.size()];
            inqty.setData(data1.toArray(array1));
            list.add(inqty);
            AxisBean outqty = new AxisBean();
            outqty.setName("出库数量");
            outqty.setName("出库TU");
            Integer[] array2 = new Integer[data2.size()];
            outqty.setData(data2.toArray(array2));
            list.add(outqty);
        }
        map.put("rows",list);
        return R.ok(map);
    }
    /**
     * 入出库按小时折线:横轴为「当前整点起向前共 12 小时」滚动窗口,与库表 ymd(yyyy-MM-dd HH)对齐
     */
    @GetMapping("/line/charts/hourly")
    public R locIoLineChartsHourly() {
        Map<String, Object> map = new HashMap<>();
        List<AxisBean> list = new ArrayList<>();
        List<WorkChartAxis> listChart = reportQueryMapper.getChartAxisHourly();
        if (listChart == null) {
            listChart = Collections.emptyList();
        }
        ArrayList<Integer> data1 = new ArrayList<>();
        ArrayList<Integer> data2 = new ArrayList<>();
        List<String> categories = new ArrayList<>();
        final int n = 12;
        SimpleDateFormat sfKey = new SimpleDateFormat("yyyy-MM-dd HH");
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.HOUR_OF_DAY, -(n - 1));
        for (int i = 0; i < n; i++) {
            String key = sfKey.format(calendar.getTime());
            categories.add(String.valueOf(calendar.get(Calendar.HOUR_OF_DAY)));
            int inV = 0;
            int outV = 0;
            for (WorkChartAxis w : listChart) {
                if (w.getYmd() != null && key.equals(w.getYmd().trim())) {
                    inV = w.getInqty();
                    outV = w.getOutqty();
                    break;
                }
            }
            data1.add(inV);
            data2.add(outV);
            calendar.add(Calendar.HOUR_OF_DAY, 1);
        }
        AxisBean inqty = new AxisBean();
        inqty.setName("入库托盘数");
        Integer[] array1 = new Integer[data1.size()];
        inqty.setData(data1.toArray(array1));
        list.add(inqty);
        AxisBean outqty = new AxisBean();
        outqty.setName("出库TU");
        Integer[] array2 = new Integer[data2.size()];
        outqty.setData(data2.toArray(array2));
        list.add(outqty);
        map.put("categories", categories);
        map.put("rows", list);
        return R.ok(map);
    }
@@ -656,7 +849,11 @@
     * 任务查询接口
     */
    @PostMapping("/queryTask")
    public synchronized R queryTask(@RequestBody QueryTaskParam param) {
    public synchronized R queryTask(@RequestBody QueryTaskParam param, HttpServletRequest request) {
        if (request != null) {
            log.info("[queryTask] cache: {}", param == null ? "null" : JSON.toJSONString(param));
            request.setAttribute("cache", param);
        }
        if (Cools.isEmpty(param)) {
            return R.parse(BaseRes.PARAM);
        }
@@ -669,12 +866,130 @@
        }
        List<WrkDetl> wrkDetls = wrkDetlService.selectByWrkNo(Integer.valueOf(param.getTaskNo()));
        String costTime = resolveCostTime(wrkMast, wrkDetls);
        HashMap<String, Object> map = new HashMap<>();
        map.put("taskNo", param.getTaskNo());
        map.put("ioType", wrkMast.getIoType());
        map.put("costTime", costTime);
        map.put("wrkDetls", wrkDetls);
        return R.ok().add(map);
    }
    private String resolveCostTime(WrkMast wrkMast, List<WrkDetl> wrkDetls) {
        Date createTime = resolveOrderCreateTime(resolveOrderNo(wrkMast, wrkDetls));
        if (createTime == null) {
            createTime = resolveTaskCreateTime(wrkMast);
        }
        if (createTime == null) {
            return "0";
        }
        long minutes = TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis() - createTime.getTime());
        if (minutes < 0L) {
            minutes = 0L;
        }
        return String.valueOf(minutes);
    }
    private String resolveOrderNo(WrkMast wrkMast, List<WrkDetl> wrkDetls) {
        if (wrkMast != null && !Cools.isEmpty(wrkMast.getUserNo())) {
            return wrkMast.getUserNo();
        }
        if (Cools.isEmpty(wrkDetls)) {
            return null;
        }
        for (WrkDetl wrkDetl : wrkDetls) {
            if (wrkDetl != null && !Cools.isEmpty(wrkDetl.getOrderNo())) {
                return wrkDetl.getOrderNo();
            }
        }
        return null;
    }
    private Date resolveOrderCreateTime(String orderNo) {
        if (Cools.isEmpty(orderNo)) {
            return null;
        }
        Date historyCreateTime = minDate(
                minCreateTime(wrkMastLogService.selectList(new EntityWrapper<WrkMastLog>().eq("user_no", orderNo))),
                minCreateTime(wrkDetlLogService.selectList(new EntityWrapper<WrkDetlLog>().eq("order_no", orderNo)))
        );
        if (historyCreateTime != null) {
            return historyCreateTime;
        }
        return minDate(
                minCreateTime(wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("user_no", orderNo))),
                minCreateTime(wrkDetlService.selectList(new EntityWrapper<WrkDetl>().eq("order_no", orderNo)))
        );
    }
    private Date minDate(Date first, Date second) {
        if (first == null) {
            return second;
        }
        if (second == null) {
            return first;
        }
        return first.before(second) ? first : second;
    }
    private Date resolveTaskCreateTime(WrkMast wrkMast) {
        if (wrkMast == null) {
            return null;
        }
        return firstDate(wrkMast.getAppeTime(), wrkMast.getIoTime(), wrkMast.getModiTime());
    }
    private Date firstDate(Date... dates) {
        if (dates == null || dates.length == 0) {
            return null;
        }
        for (Date date : dates) {
            if (date != null) {
                return date;
            }
        }
        return null;
    }
    private Date minCreateTime(List<?> list) {
        if (Cools.isEmpty(list)) {
            return null;
        }
        Date min = null;
        for (Object item : list) {
            Date createTime = resolveCreateTime(item);
            if (createTime == null) {
                continue;
            }
            if (min == null || createTime.before(min)) {
                min = createTime;
            }
        }
        return min;
    }
    private Date resolveCreateTime(Object item) {
        if (item instanceof WrkMast) {
            WrkMast wrkMast = (WrkMast) item;
            return firstDate(wrkMast.getAppeTime(), wrkMast.getIoTime(), wrkMast.getModiTime());
        }
        if (item instanceof WrkMastLog) {
            WrkMastLog wrkMastLog = (WrkMastLog) item;
            return firstDate(wrkMastLog.getAppeTime(), wrkMastLog.getIoTime(), wrkMastLog.getModiTime());
        }
        if (item instanceof WrkDetl) {
            WrkDetl wrkDetl = (WrkDetl) item;
            return firstDate(wrkDetl.getAppeTime(), wrkDetl.getIoTime(), wrkDetl.getModiTime());
        }
        if (item instanceof WrkDetlLog) {
            WrkDetlLog wrkDetlLog = (WrkDetlLog) item;
            return firstDate(wrkDetlLog.getAppeTime(), wrkDetlLog.getIoTime(), wrkDetlLog.getModiTime());
        }
        return null;
    }
}