From d0226747665355acecd5b4f2b5c0beb020586729 Mon Sep 17 00:00:00 2001
From: skyouc
Date: 星期五, 17 一月 2025 15:37:32 +0800
Subject: [PATCH] # 23. PDA拣货单据,勾选或点击确认按钮后,完成当前单据 (已完成) 24. PDA出库成功后,界面数据重置,避免重复操作  (已修复) 25. PDA接口请求,添加一个Loading遮档  (已修复) 27. 非平库单据,在平库可做入库操作  (已修复) 28. 平库已组拖数据,组拖完成后依然可组拖  (已修复) 29. 平库入库后,订单明细没有添加(已修复) 30. 平库入库后,单据类型没有修改(已修复) 31. 没有绑定播种位,不能进行播种,前后端都需加判定(已修复) 33. 平库入库未修改入库已完成数量(已修复) 34. cacheSite缓存站点逻辑需重新梳理,入库生成波次时(已完成) 35. PDA添加发货确认,默认全选 (已修复) 36. 大屏获取任务时,是由容器到达的拖盘码确认通知 (已修复) 37. 拣货单序号不显示 问题修复 (已修复) 42. pda发货确认,添加不同颜色区分是否全部完成拣货,绿色全部拣货完成,红色完成部分拣货(已修复) 43. CTU入库完成后,订单明细没有删除,执行中数量清空(已修复) 44. 平库入库完成后,历史档明细完成数量没有更新 (已修复) 45. PDA料号不显示  (已修复) 46. 发货完成后,波次管理数据未加入历史档 (已修复)

---
 zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/manage/OutManage.java | 1546 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 1,397 insertions(+), 149 deletions(-)

diff --git a/zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/manage/OutManage.java b/zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/manage/OutManage.java
index b84d50a..e5e77a4 100644
--- a/zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/manage/OutManage.java
+++ b/zy-asrs-wms/src/main/java/com/zy/asrs/wms/asrs/manage/OutManage.java
@@ -1,149 +1,1397 @@
-package com.zy.asrs.wms.asrs.manage;
-
-import com.zy.asrs.framework.exception.CoolException;
-import com.zy.asrs.wms.asrs.controller.req.OutReq;
-import com.zy.asrs.wms.asrs.entity.*;
-import com.zy.asrs.wms.asrs.entity.param.FieldParam;
-import com.zy.asrs.wms.asrs.service.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * 鍑哄簱绠$悊
- */
-@Service
-public class OutManage {
-
-    private static Logger logger = LoggerFactory.getLogger(LocManage.class);
-
-    @Autowired
-    private TaskService taskService;
-
-
-    @Autowired
-    private TaskDetlService taskDetlService;
-
-    @Autowired
-    private LocService locService;
-
-
-    @Autowired
-    private LocDetlService locDetlService;
-
-
-    @Autowired
-    private WorkService workService;
-
-
-    @Autowired
-    private OrderService orderService;
-
-    @Autowired
-    private OrderDetlService orderDetlService;
-
-
-    /**
-     * 鑾峰彇搴撳瓨
-     *
-     * @param map
-     */
-    public List<LocDetl> listSuitableMat(Map<String, Object> map) {
-        List<FieldParam> param = new ArrayList<>();
-        map.entrySet().stream().filter(entry -> entry.getValue() != null).forEach(entry -> {
-            FieldParam fieldParam = new FieldParam();
-            fieldParam.setName(entry.getKey());
-            fieldParam.setValue(entry.getValue());
-            param.add(fieldParam);
-        });
-        //TODO 杩欓噷鍔犱笂鍑哄簱瑙勫垯
-
-        List<LocDetl> stock = locDetlService.listSuitableMat(param, null);
-        return stock;
-    }
-
-    /**
-     * 鏍规嵁璁㈠崟id鑾峰彇搴撳瓨
-     *
-     * @param orderId 璁㈠崟ID
-     */
-    public List<LocDetl> listSuitableMatByOrder(Long orderId) {
-        Order order = orderService.getById(orderId);
-        List<OrderDetl> orderDetls = orderDetlService.getOrderDetlByOrderId(orderId);
-        //TODO 杩欓噷鍔犱笂鍑哄簱瑙勫垯
-        for (OrderDetl orderDetl : orderDetls) {
-
-        }
-        List<FieldParam> param = new ArrayList<>();
-
-
-        List<LocDetl> stock = locDetlService.listSuitableMat(param, null);
-        return stock;
-    }
-
-    /**
-     * 鏍规嵁璁㈠崟id鑾峰彇搴撳瓨
-     *
-     * @param waveId 璁㈠崟ID
-     */
-    public List<LocDetl> listSuitableMatByWave(Long waveId) {
-
-        List<FieldParam> param = new ArrayList<>();
-
-
-        List<LocDetl> stock = locDetlService.listSuitableMat(param, null);
-        return stock;
-    }
-
-    /**
-     * 鍑哄簱
-     *
-     * @param outReq
-     */
-    public void out(OutReq outReq) {
-        Map<Long, List<OutReq.Detl>> map = outReq.getDetls().stream().collect(Collectors.groupingBy(OutReq.Detl::getLocDetlId));
-        map.forEach((k, v) -> {
-            Loc loc = locService.getById(k);
-            processTask(loc, v, outReq.getTargetSite());
-        });
-    }
-
-
-    private void processTask(Loc loc, List<OutReq.Detl> detls, String targetSite) {
-        // 淇濆瓨宸ヤ綔妗�
-        Task task = new Task();
-        task.setTaskNo(workService.generateTaskNo(1L));
-        // 浠诲姟鐘舵��
-        task.setTaskSts(101L);
-        // 浠诲姟绫诲瀷
-        task.setTaskType(101L);
-        // 浼樺厛绾�
-        task.setIoPri(1);
-        // 婧愬簱浣�
-        task.setOriginLoc(loc.getLocNo());
-        // 鐩爣绔欑偣
-        task.setTargetSite(targetSite);
-        // 鎵樼洏鐮�
-        task.setBarcode(loc.getBarcode());
-        boolean res = taskService.save(task);
-        if (!res) {
-            throw new CoolException("淇濆瓨宸ヤ綔妗eけ璐�");
-        }
-        // 宸ヤ綔妗f槑缁嗕繚瀛�
-        for (OutReq.Detl detl : detls) {
-            LocDetl locDetl = locDetlService.getById(detl.getLocDetlId());
-            TaskDetl taskDetl = new TaskDetl();
-            taskDetl.sync(locDetl);
-            taskDetl.setTaskId(task.getId());
-            if (!taskDetlService.save(taskDetl)) {
-                throw new CoolException("淇濆瓨宸ヤ綔妗f槑缁嗗け璐�");
-            }
-        }
-    }
-}
+package com.zy.asrs.wms.asrs.manage;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.mysql.cj.util.StringUtils;
+import com.zy.asrs.framework.exception.CoolException;
+import com.zy.asrs.wms.asrs.entity.dto.*;
+import com.zy.asrs.wms.asrs.entity.dto.OrderOutMergeDto;
+import com.zy.asrs.wms.asrs.entity.enums.*;
+import com.zy.asrs.wms.asrs.entity.param.*;
+import com.zy.asrs.wms.asrs.entity.*;
+import com.zy.asrs.wms.asrs.service.*;
+import com.zy.asrs.wms.utils.OrderUtils;
+import com.zy.asrs.wms.utils.OutUtils;
+import com.zy.asrs.wms.utils.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * 鍑哄簱绠$悊
+ */
+@Service
+public class OutManage {
+
+    private static Logger logger = LoggerFactory.getLogger(LocManage.class);
+
+    @Autowired
+    private TaskService taskService;
+    @Autowired
+    private TaskDetlService taskDetlService;
+    @Autowired
+    private TaskDetlFieldService taskDetlFieldService;
+    @Autowired
+    private LocService locService;
+    @Autowired
+    private LocDetlService locDetlService;
+    @Autowired
+    private LocDetlFieldService locDetlFieldService;
+    @Autowired
+    private WorkService workService;
+    @Autowired
+    private OrderService orderService;
+    @Autowired
+    private OrderDetlService orderDetlService;
+    @Autowired
+    private OutUtils outUtils;
+    @Autowired
+    private OperationPortService operationPortService;
+    @Autowired
+    private OrderUtils orderUtils;
+    @Autowired
+    private OrderNoRuleService orderNoRuleService;
+    @Autowired
+    private WaveService waveService;
+    @Autowired
+    private WaveDetlService waveDetlService;
+    @Autowired
+    private CacheSiteService cacheSiteService;
+    @Autowired
+    private WaveSeedService waveSeedService;
+    @Autowired
+    private PickSheetService pickSheetService;
+    @Autowired
+    private PickSheetDetlService pickSheetDetlService;
+    @Autowired
+    private MatService matService;
+
+    /**
+     * 鍑哄簱
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void out(OutParam outParam) {
+        if (outParam.getOperationPort() == null) {
+            throw new CoolException("浣滀笟鍙d笉瀛樺湪");
+        }
+
+        List<OutLocDto> list = outUtils.merge(outParam);
+        processTask(list);
+    }
+
+    private void processTask(List<OutLocDto> list) {
+        for (OutLocDto locDto : list) {
+            long taskType = locDto.getAll() ? 101L : 103L;
+
+            Loc loc = locService.getById(locDto.getLocId());
+            if (loc == null) {
+                throw new CoolException("搴撲綅涓嶅瓨鍦�");
+            }
+
+            if (!loc.getLocStsId().equals(LocStsType.F.val())) {
+                throw new CoolException("搴撲綅鐘舵�佷笉鍦ㄥ簱");
+            }
+
+            Task task = new Task();
+            task.setTaskNo(workService.generateTaskNo(1L));
+            task.setTaskSts(TaskStsType.GENERATE_OUT.id);
+            task.setTaskType(taskType);
+            task.setIoPri(workService.generateIoPri(taskType));
+            task.setOriginLoc(loc.getLocNo());
+            task.setTargetSite(locDto.getOperationPort());
+            task.setBarcode(loc.getBarcode());
+            boolean res = taskService.save(task);
+            if (!res) {
+                throw new CoolException("淇濆瓨宸ヤ綔妗eけ璐�");
+            }
+            // 宸ヤ綔妗f槑缁嗕繚瀛�
+            for (OutDetlDto detl : locDto.getDetls()) {
+                LocDetl locDetl = locDetlService.getById(detl.getDetlId());
+                if (locDetl == null) {
+                    throw new CoolException("鏄庣粏涓嶅瓨鍦�");
+                }
+
+                OrderDetl orderDetl = orderDetlService.getById(detl.getOrderDetlId());
+                if (orderDetl == null) {
+                    throw new CoolException("鏄庣粏涓嶅瓨鍦�");
+                }
+
+                TaskDetl taskDetl = new TaskDetl();
+                taskDetl.sync(locDetl);
+                taskDetl.setTaskId(task.getId());
+                taskDetl.setTaskNo(task.getTaskNo());
+                taskDetl.setAnfme(detl.getAnfme());
+                taskDetl.setStock(detl.getStock());
+                taskDetl.setOrderId(null);
+                taskDetl.setOrderNo(null);
+                if (!taskDetlService.save(taskDetl)) {
+                    throw new CoolException("淇濆瓨宸ヤ綔妗f槑缁嗗け璐�");
+                }
+
+                List<LocDetlField> locDetlFields = locDetlFieldService.list(new LambdaQueryWrapper<LocDetlField>().eq(LocDetlField::getDetlId, locDetl.getId()));
+                for (LocDetlField locDetlField : locDetlFields) {
+                    TaskDetlField taskDetlField = new TaskDetlField();
+                    taskDetlField.sync(locDetlField);
+                    taskDetlField.setDetlId(taskDetl.getId());
+                    boolean taskDetlFieldSave = taskDetlFieldService.save(taskDetlField);
+                    if (!taskDetlFieldSave) {
+                        throw new CoolException("鏄庣粏鎵╁睍鐢熸垚澶辫触");
+                    }
+                }
+            }
+
+            //搴撲綅F => R
+            loc.setLocStsId(LocStsType.R.val());
+            loc.setUpdateTime(new Date());
+            boolean locUpdate = locService.updateById(loc);
+            if (!locUpdate) {
+                throw new CoolException("搴撲綅鐘舵�佹洿鏂板け璐�");
+            }
+        }
+    }
+
+    public List<OrderOutBatchPreviewDto> orderOutBatchPreview(OrderOutBatchPreviewParam param) {
+        List<Long> orderDetlIds = param.getOrderDetlIds();
+        if (orderDetlIds.isEmpty()) {
+            throw new CoolException("璁㈠崟鏄庣粏涓嶈兘涓虹┖");
+        }
+        List<OrderDetl> orderDetls = orderDetlService.list(new LambdaQueryWrapper<OrderDetl>().in(OrderDetl::getId, orderDetlIds).orderByAsc(OrderDetl::getOrderNo, OrderDetl::getCreateTime));
+        if (orderDetls.isEmpty()) {
+            throw new CoolException("璁㈠崟鏄庣粏涓嶅瓨鍦�");
+        }
+        orderDetls = orderDetlService.parseDetl(orderDetls);
+
+        HashMap<Long, List<LocDetl>> orderDetlLocMap = new HashMap<>();
+//        //鍑哄簱璁㈠崟鍚堣
+        List<OutDetlDto> detlDtos = new ArrayList<>();
+//        //鑾峰彇骞充粨涓鍚堟潯浠剁殑鎵�鏈夊簱浣�
+//        orderDetls.forEach(detl -> {
+//            double issued = Optional.of(detl.getAnfme() - detl.getQty() - detl.getWorkQty()).orElse(0.0D);
+//            if (issued <= 0.0D) {
+//                return;
+//            }
+//            List<LocDetl> locs = locDetlService.queryFlatStock(detl.getMat$().getMatnr(), detl.getBatch(), detl.getUniqueField());
+//            //骞冲簱鏈夊綋鏄庣墿鏂欎紭鍏堝嚭搴�
+//            if (!locs.isEmpty()) {
+//                for (LocDetl locDetl : locs) {
+//                    if (issued > 0) {
+//                        OutDetlDto outDetlDto = new OutDetlDto();
+//                        outDetlDto.setDetlId(locDetl.getId());
+//                        outDetlDto.setAnfme(issued >= locDetl.getAnfme() ? locDetl.getAnfme() : issued);
+//                        outDetlDto.setStock(locDetl.getAnfme());
+//                        outDetlDto.setOrderDetlId(locDetl.getId());
+//                        detlDtos.add(outDetlDto);
+//                        issued = issued - outDetlDto.getAnfme();
+//                    }
+//                }
+//                //璁㈠崟鏄庣粏闇�鍑哄簱鏁伴噺
+//                double workQty = Optional.of(detl.getAnfme() - detl.getQty() - detl.getWorkQty()).orElse(0.0D);
+//                //鏇存柊骞冲簱璁㈠崟鏄庣粏鐨勫疄闄呭彲鐢ㄦ暟閲�
+//                detl.setWorkQty(workQty - issued);
+//            }
+//        });
+
+        /**
+         * 骞冲簱浼樺厛鍑哄簱瀹屾垚鍚庯紝褰撹鍗曟槑缁唚orkQty + qty 杩樹笉绛変簬anfme鏃讹紝鏌ヨTCU搴�
+         */
+        //鑾峰彇TCU绗﹀悎鏉′欢搴撲綅
+        for (OrderDetl orderDetl : orderDetls) {
+            double issued = Optional.of(orderDetl.getAnfme() - orderDetl.getQty() - orderDetl.getWorkQty()).orElse(0.0D);
+            if (issued <= 0.0D) {
+                continue;
+            }
+            List<LocDetl> locDetls = locDetlService.queryStock(orderDetl.getMat$().getMatnr(), orderDetl.getBatch(), orderDetl.getUniqueField());
+            orderDetlLocMap.put(orderDetl.getId(), locDetls);
+            for (LocDetl locDetl : locDetls) {
+                if (issued > 0) {
+                    OutDetlDto outDetlDto = new OutDetlDto();
+                    outDetlDto.setDetlId(locDetl.getId());
+                    outDetlDto.setAnfme(issued >= locDetl.getAnfme() ? locDetl.getAnfme() : issued);
+                    outDetlDto.setStock(locDetl.getAnfme());
+                    outDetlDto.setOrderDetlId(orderDetl.getId());
+                    detlDtos.add(outDetlDto);
+                    issued = issued - outDetlDto.getAnfme();
+                } else {
+                    break;
+                }
+            }
+        }
+
+        HashMap<Long, List<OutDetlDto>> map = new HashMap<>();
+        for (OutDetlDto detlDto : detlDtos) {
+            LocDetl locDetl = locDetlService.getById(detlDto.getDetlId());
+            List<OutDetlDto> dtos = map.get(locDetl.getLocId());
+            if (dtos == null) {
+                dtos = new ArrayList<>();
+                dtos.add(detlDto);
+            } else {
+                dtos.add(detlDto);
+            }
+            map.put(locDetl.getLocId(), dtos);
+        }
+
+        List<Long> orderDetlIdsTmp = param.getOrderDetlIds();
+        List<OrderOutBatchPreviewDto> previewDtos = new ArrayList<>();
+        for (Map.Entry<Long, List<OutDetlDto>> entry : map.entrySet()) {
+            Long locId = entry.getKey();
+            Loc loc = locService.getById(locId);
+
+            List<OutDetlDto> outDetlDtos = entry.getValue();
+            for (OutDetlDto outDetlDto : outDetlDtos) {
+                orderDetlIdsTmp.remove(outDetlDto.getOrderDetlId());
+            }
+            Boolean all = outUtils.isAllForOut(locId, outDetlDtos);
+
+            for (OutDetlDto outDetlDto : outDetlDtos) {
+                OrderOutBatchPreviewDto previewDto = new OrderOutBatchPreviewDto();
+                previewDto.setLocId(locId);
+                previewDto.setLocNo(loc.getLocNo());
+                previewDto.setLocDetlId(outDetlDto.getDetlId());
+                previewDto.setAll(all);
+                previewDto.setAnfme(outDetlDto.getAnfme());
+                previewDto.setStock(outDetlDto.getStock());
+                previewDto.setOrderDetlId(outDetlDto.getOrderDetlId());
+                previewDtos.add(previewDto);
+
+
+                List<BatchPreviewOtherLocDto> otherLocs = new ArrayList<>();
+                previewDto.setOtherLoc(otherLocs);
+
+                List<LocDetl> locDetls = orderDetlLocMap.get(outDetlDto.getOrderDetlId());
+                for (LocDetl locDetl : locDetls) {
+                    BatchPreviewOtherLocDto otherLocDto = new BatchPreviewOtherLocDto();
+                    otherLocDto.setLocId(locDetl.getLocId());
+                    otherLocDto.setLocNo(locDetl.getLocNo());
+                    otherLocDto.setStock(locDetl.getAnfme());
+                    otherLocDto.setLocDetlId(locDetl.getId());
+
+                    if (locDetl.getLocId().equals(locId)) {
+                        otherLocs.add(0, otherLocDto);
+                        continue;
+                    }
+
+                    if (otherLocs.isEmpty()) {
+                        otherLocs.add(otherLocDto);
+                    }
+
+                    for (int i = 0; i < otherLocs.size(); i++) {
+                        BatchPreviewOtherLocDto locDto = otherLocs.get(i);
+                        if (locDto.getLocId().equals(locDetl.getLocId())) {
+                            break;
+                        }
+                        otherLocs.add(otherLocDto);
+                    }
+                }
+            }
+
+        }
+
+        for (Long id : orderDetlIdsTmp) {
+            OrderDetl orderDetl = orderDetlService.getById(id);
+            double issued = Optional.of(orderDetl.getAnfme() - orderDetl.getQty() - orderDetl.getWorkQty()).orElse(0.0D);
+
+            OrderOutBatchPreviewDto previewDto = new OrderOutBatchPreviewDto();
+            previewDto.setLocId(null);
+            previewDto.setLocNo(null);
+            previewDto.setLocDetlId(null);
+            previewDto.setAll(null);
+            previewDto.setAnfme(issued);
+            previewDto.setStock(0D);
+            previewDto.setOrderDetlId(orderDetl.getId());
+
+            previewDtos.add(previewDto);
+        }
+
+        return previewDtos;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void orderOutBatch(List<OrderOutBatchPreviewDto> param) {
+        if (param == null) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        if (param.isEmpty()) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        boolean noStock = true;
+        for (OrderOutBatchPreviewDto dto : param) {
+            if (dto.getStock() > 0) {
+                noStock = false;
+                break;
+            }
+        }
+        if (noStock) {
+            throw new CoolException("搴撳瓨涓嶈冻");
+        }
+
+
+        HashMap<Long, List<OrderOutBatchPreviewDto>> detlMap = new HashMap<>();
+        for (OrderOutBatchPreviewDto previewDto : param) {
+            if (previewDto.getLocId() == null) {
+                continue;
+            }
+
+            if (detlMap.containsKey(previewDto.getLocDetlId())) {
+                List<OrderOutBatchPreviewDto> previewDtos = detlMap.get(previewDto.getLocDetlId());
+                previewDtos.add(previewDto);
+                detlMap.put(previewDto.getLocDetlId(), previewDtos);
+            } else {
+                List<OrderOutBatchPreviewDto> previewDtos = new ArrayList<>();
+                previewDtos.add(previewDto);
+                detlMap.put(previewDto.getLocDetlId(), previewDtos);
+            }
+        }
+
+        List<OrderOutBatchPreviewDto> dtos = new ArrayList<>();
+        for (Map.Entry<Long, List<OrderOutBatchPreviewDto>> entry : detlMap.entrySet()) {
+            Long locDetlId = entry.getKey();
+            LocDetl locDetl = locDetlService.getById(locDetlId);
+            if (locDetl == null) {
+                continue;
+            }
+
+            Double stock = locDetl.getAnfme();
+            for (OrderOutBatchPreviewDto dto : entry.getValue()) {
+                stock = stock - dto.getAnfme();
+                if (stock >= 0) {
+                    dtos.add(dto);
+                }
+            }
+        }
+
+
+        HashMap<Long, List<OrderOutBatchPreviewDto>> map = new HashMap<>();
+
+        for (OrderOutBatchPreviewDto previewDto : dtos) {
+            if (map.containsKey(previewDto.getLocId())) {
+                List<OrderOutBatchPreviewDto> previewDtos = map.get(previewDto.getLocId());
+                previewDtos.add(previewDto);
+                map.put(previewDto.getLocId(), previewDtos);
+            } else {
+                List<OrderOutBatchPreviewDto> previewDtos = new ArrayList<>();
+                previewDtos.add(previewDto);
+                map.put(previewDto.getLocId(), previewDtos);
+            }
+        }
+
+        for (Map.Entry<Long, List<OrderOutBatchPreviewDto>> entry : map.entrySet()) {
+            Long locId = entry.getKey();
+            List<OrderOutBatchPreviewDto> previewDtos = entry.getValue();
+            Boolean all = outUtils.isAllForPreview(locId, previewDtos);
+            OrderOutBatchPreviewDto previewDto = previewDtos.get(0);
+            Long operationPortId = previewDto.getOperationPort();
+
+            Loc loc = locService.getById(locId);
+            if (loc == null) {
+                continue;
+            }
+
+            if (!loc.getLocStsId().equals(LocStsType.F.val())) {
+                continue;
+            }
+
+            OperationPort operationPort = operationPortService.getById(operationPortId);
+            if (operationPort == null) {
+                throw new CoolException("浣滀笟鍙d笉瀛樺湪");
+            }
+
+
+            long taskType = all ? 101L : 103L;
+
+            Task task = new Task();
+            task.setTaskNo(workService.generateTaskNo(taskType));
+            task.setTaskSts(TaskStsType.GENERATE_OUT.id);
+            task.setTaskType(taskType);
+            task.setIoPri(workService.generateIoPri(taskType));
+            task.setOriginLoc(loc.getLocNo());
+            task.setTargetSite(operationPort.getFlag());
+            task.setBarcode(loc.getBarcode());
+            boolean res = taskService.save(task);
+            if (!res) {
+                throw new CoolException("淇濆瓨宸ヤ綔妗eけ璐�");
+            }
+
+            for (OrderOutBatchPreviewDto dto : previewDtos) {
+                LocDetl locDetl = locDetlService.getById(dto.getLocDetlId());
+                if (locDetl == null) {
+                    throw new CoolException("鏄庣粏涓嶅瓨鍦�");
+                }
+
+                OrderDetl orderDetl = orderDetlService.getById(dto.getOrderDetlId());
+                if (orderDetl == null) {
+                    throw new CoolException("璁㈠崟鏄庣粏涓嶅瓨鍦�");
+                }
+                orderUtils.updateWorkQty(dto.getOrderDetlId(), dto.getAnfme());
+
+                TaskDetl taskDetl = new TaskDetl();
+                taskDetl.sync(locDetl);
+                taskDetl.setId(null);
+                taskDetl.setTaskId(task.getId());
+                taskDetl.setTaskNo(task.getTaskNo());
+                taskDetl.setAnfme(dto.getAnfme());
+                taskDetl.setStock(locDetl.getAnfme());
+                taskDetl.setOrderId(orderDetl.getOrderId());
+                taskDetl.setOrderNo(orderDetl.getOrderNo());
+                taskDetl.setDetlId(orderDetl.getId());
+                if (!taskDetlService.save(taskDetl)) {
+                    throw new CoolException("淇濆瓨宸ヤ綔妗f槑缁嗗け璐�");
+                }
+
+                List<LocDetlField> locDetlFields = locDetlFieldService.list(new LambdaQueryWrapper<LocDetlField>().eq(LocDetlField::getDetlId, locDetl.getId()));
+                for (LocDetlField locDetlField : locDetlFields) {
+                    TaskDetlField taskDetlField = new TaskDetlField();
+                    taskDetlField.sync(locDetlField);
+                    taskDetlField.setId(null);
+                    taskDetlField.setDetlId(taskDetl.getId());
+                    boolean taskDetlFieldSave = taskDetlFieldService.save(taskDetlField);
+                    if (!taskDetlFieldSave) {
+                        throw new CoolException("鏄庣粏鎵╁睍鐢熸垚澶辫触");
+                    }
+                }
+            }
+
+            //搴撲綅F => R
+            loc.setLocStsId(LocStsType.R.val());
+            loc.setUpdateTime(new Date());
+            boolean locUpdate = locService.updateById(loc);
+            if (!locUpdate) {
+                throw new CoolException("搴撲綅鐘舵�佹洿鏂板け璐�");
+            }
+
+        }
+
+    }
+
+    @Transactional
+    public List<MergePreviewDto> orderOutMergePreview(OrderOutMergePreviewParam param) {
+        if (param == null) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        List<Long> orderIds = param.getOrderIds();
+        if (orderIds.isEmpty()) {
+            throw new CoolException("璁㈠崟涓嶈兘涓虹┖");
+        }
+
+        List<Order> orders = orderService.list(new LambdaQueryWrapper<Order>().in(Order::getId, orderIds));
+        if (orders.isEmpty()) {
+            throw new CoolException("璁㈠崟涓嶅瓨鍦�");
+        }
+
+        List<OrderDetl> orderDetls = orderDetlService.list(new LambdaQueryWrapper<OrderDetl>().in(OrderDetl::getOrderId, orderIds));
+        if (orderDetls.isEmpty()) {
+            throw new CoolException("璁㈠崟鏄庣粏涓嶅瓨鍦�");
+        }
+        orderDetls = orderDetlService.parseDetl(orderDetls);
+
+        HashMap<String, Double> locDetlStockMap = new HashMap<>();
+        for (OrderDetl orderDetl : orderDetls) {
+            String matUniqueKey = Utils.getMatUniqueKey(orderDetl.getMat$().getMatnr(), orderDetl.getBatch(), orderDetl.getUniqueField());
+            double issued = Optional.of(orderDetl.getAnfme() - orderDetl.getQty() - orderDetl.getWorkQty()).orElse(0.0D);
+            if (locDetlStockMap.containsKey(matUniqueKey)) {
+                Double anfme = locDetlStockMap.get(matUniqueKey);
+                anfme += issued;
+                locDetlStockMap.put(matUniqueKey, anfme);
+            } else {
+                locDetlStockMap.put(matUniqueKey, issued);
+            }
+        }
+
+        List<MergePreviewDto> mergePreviewDtos = new ArrayList<>();
+        for (Map.Entry<String, Double> entry : locDetlStockMap.entrySet()) {
+            String matUniqueKey = entry.getKey();
+            Double anfme = entry.getValue();
+
+            MatUniqueObjDto matUniqueObj = Utils.getMatUniqueObj(matUniqueKey);
+            HashMap<String, Object> dynamicFields = new HashMap<>();
+            for (FieldParam fieldParam : matUniqueObj.getParams()) {
+                dynamicFields.put(fieldParam.getName(), fieldParam.getValue());
+            }
+
+            MergePreviewDto dto = new MergePreviewDto();
+            dto.setMatnr(matUniqueObj.getMatnr());
+            dto.setBatch(matUniqueObj.getBatch());
+            dto.setAnfme(anfme);
+            dto.setOrderIds(orderIds);
+            dto.setFieldParamsEncode(JSON.toJSONString(matUniqueObj.getParams()));
+            dto.setDynamicFields(dynamicFields);
+            mergePreviewDtos.add(dto);
+        }
+
+        return mergePreviewDtos;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public List<MergePreviewResultDto> orderOutMergeLocPreview(List<MergePreviewDto> param) {
+        if (param == null) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        if (param.isEmpty()) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        for (MergePreviewDto dto : param) {
+            List<FieldParam> fieldParams = JSON.parseArray(dto.getFieldParamsEncode(), FieldParam.class);
+            dto.setFieldParams(fieldParams);
+        }
+
+        FieldSortParam sortParam = new FieldSortParam("anfme", "desc");
+        List<FieldSortParam> sortParams = new ArrayList<>();
+        sortParams.add(sortParam);
+
+        List<MergePreviewResultDto> resultDtos = new ArrayList<>();
+        //浼樺厛鏌ヨ骞冲簱鏁版嵁
+        param.forEach(pars -> {
+            List<MergePreviewResultLocDto> locDtos = new ArrayList<>();
+            MergePreviewResultDto resultDto = new MergePreviewResultDto();
+            resultDto.sync(pars);
+            resultDto.setOrderIds(pars.getOrderIds());
+            resultDto.setLocs(locDtos);
+
+            List<LocDetl> locs = locDetlService.queryFlatStock(pars.getMatnr(), pars.getBatch(), pars.getFieldParams());
+            if (!locs.isEmpty()) {
+                double anfme = pars.getAnfme() - pars.getWorkQty();
+                for (LocDetl detl : locs) {
+                    Loc loc = locService.getById(detl.getLocId());
+                    if (loc == null) {
+                        throw new CoolException("搴撲綅鏁版嵁涓嶅瓨鍦�");
+                    }
+
+                    if (loc.getLocStsId() != LocStsType.F.val()) {
+                        continue;
+                    }
+                    MergePreviewResultLocDto locDto = new MergePreviewResultLocDto();
+                    locDto.setLocId(detl.getLocId());
+                    locDto.setLocNo(detl.getLocNo());
+                    locDto.setTypeId(LocAreaTypeSts.LOC_AREA_TYPE_FLAT.id);
+                    locDto.setLocDetlId(detl.getId());
+
+                    locDtos.add(locDto);
+                    //搴撲綅瀹為檯鍙敤鏁伴噺
+                    double surplusQty = detl.getAnfme() - detl.getWorkQty();
+                    //娉㈡鏁伴噺鍑忓幓搴撲綅鍙敤鏁伴噺鍚庯紝鐩堜綑鏁伴噺
+                    anfme = anfme - surplusQty;
+                    if (anfme > 0) {
+                        locDto.setAnfme(detl.getAnfme());
+                        locDto.setWorkQty(surplusQty);
+                    } else {
+                        locDto.setAnfme(pars.getAnfme() - pars.getWorkQty());
+                        locDto.setWorkQty(pars.getAnfme() - pars.getWorkQty());
+                        break;
+                    }
+                }
+                //淇濆瓨鍑哄簱鏁伴噺锛堝钩搴擄級
+                pars.setWorkQty(pars.getAnfme() - pars.getWorkQty() - anfme);
+
+                resultDto.setOtherLocs(new ArrayList<>());
+
+                resultDto.setAnfme(pars.getAnfme());
+
+                resultDtos.add(resultDto);
+
+            }
+        });
+        //骞冲簱鏌ヨ瀹屾垚鍚庯紝鍐嶆煡璇CU
+        for (MergePreviewDto dto : param) {
+            Double anfme = dto.getAnfme() - dto.getWorkQty();
+            //鍑忓幓骞冲簱鏁伴噺鍚庯紝灏忎簬绛変簬0锛岃烦鍑哄鐞�
+            if (anfme <= 0) {
+                continue;
+            }
+            List<LocDetl> locDetls = locDetlService.queryStock(dto.getMatnr(), dto.getBatch(), dto.getFieldParams(), sortParams);
+            if (locDetls.isEmpty()) {
+                MergePreviewResultDto resultDto = new MergePreviewResultDto();
+                resultDto.sync(dto);
+                resultDto.setLocs(new ArrayList<>());
+                resultDto.setOrderIds(dto.getOrderIds());
+                resultDto.setAnfme(dto.getAnfme());
+                resultDtos.add(resultDto);
+                continue;
+            }
+
+            List<MergePreviewResultLocDto> locDtos = new ArrayList<>();
+
+            MergePreviewResultDto resultDto = new MergePreviewResultDto();
+            resultDto.sync(dto);
+            resultDto.setOrderIds(dto.getOrderIds());
+//            Double anfme = dto.getAnfme();
+            resultDto.setLocs(locDtos);
+            for (LocDetl locDetl : locDetls) {
+                Loc loc = locService.getById(locDetl.getLocId());
+                if (loc == null) {
+                    throw new CoolException("搴撲綅鏁版嵁涓嶅瓨鍦�");
+                }
+
+                if (loc.getLocStsId() != LocStsType.F.val()) {
+                    continue;
+                }
+
+                MergePreviewResultLocDto locDto = new MergePreviewResultLocDto();
+                locDto.setLocId(locDetl.getLocId());
+                locDto.setLocNo(locDetl.getLocNo());
+                locDto.setLocDetlId(locDetl.getId());
+                locDto.setTypeId(LocAreaTypeSts.LOC_AREA_TYPE_UTC.id);
+                locDtos.add(locDto);
+                if (anfme - locDetl.getAnfme() < 0) {
+                    locDto.setAnfme(anfme);
+                    break;
+                }
+                locDto.setAnfme(locDetl.getAnfme());
+                anfme -= locDetl.getAnfme();
+            }
+
+            List<MergePreviewResultLocDto> otherLocDtos = new ArrayList<>();
+            for (LocDetl locDetl : locDetls) {
+                Loc loc = locService.getById(locDetl.getLocId());
+                if (loc == null) {
+                    throw new CoolException("搴撲綅鏁版嵁涓嶅瓨鍦�");
+                }
+
+                if (loc.getLocStsId() != LocStsType.F.val()) {
+                    continue;
+                }
+
+                MergePreviewResultLocDto locDto = new MergePreviewResultLocDto();
+                locDto.setLocId(locDetl.getLocId());
+                locDto.setLocNo(locDetl.getLocNo());
+                locDto.setTypeId(LocAreaTypeSts.LOC_AREA_TYPE_UTC.id);
+                locDto.setLocDetlId(locDetl.getId());
+                locDto.setAnfme(locDetl.getAnfme());
+                otherLocDtos.add(locDto);
+            }
+            resultDto.setOtherLocs(otherLocDtos);
+
+            resultDto.setAnfme(dto.getAnfme());
+
+            resultDtos.add(resultDto);
+        }
+
+        return resultDtos;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void orderOutMerge(OrderOutMergeParamDto dto) {
+        if (dto == null) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        List<OrderOutMergeParam> params = dto.getList();
+
+        if (params.isEmpty()) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        List<Long> orderIds = null;
+
+        List<OrderOutMergeParam> filterParam = new ArrayList<>();
+        HashMap<String, OrderOutMergeParam> paramMap = new HashMap<>();
+        for (OrderOutMergeParam param : params) {
+            if (param.getLocId() == null) {
+                continue;
+            }
+
+            filterParam.add(param);
+
+            String matUniqueKey = Utils.getMatUniqueKey(param.getMatnr(), param.getBatch(), param.getFieldParams());
+            paramMap.put(matUniqueKey, param);
+
+            if (orderIds == null) {
+                orderIds = param.getOrderIds();
+            }
+        }
+
+        if (orderIds == null) {
+            throw new CoolException("璁㈠崟涓嶅瓨鍦�");
+        }
+
+        List<Order> orderList = orderService.listByIds(orderIds);
+        if (orderList.isEmpty()) {
+            throw new CoolException("璁㈠崟涓嶅瓨鍦�");
+        }
+
+        List<OrderDetl> orderDetls = orderDetlService.list(new LambdaQueryWrapper<OrderDetl>().in(OrderDetl::getOrderId, orderIds));
+        if (orderDetls.isEmpty()) {
+            throw new CoolException("璁㈠崟鏄庣粏涓嶅瓨鍦�");
+        }
+
+        HashMap<String, List<OrderDetl>> detlMap = new HashMap<>();
+        for (OrderDetl orderDetl : orderDetls) {
+            String matUniqueKey = Utils.getMatUniqueKey(orderDetl.getMat$().getMatnr(), orderDetl.getBatch(), orderDetl.getUniqueField());
+            if (detlMap.containsKey(matUniqueKey)) {
+                List<OrderDetl> detls = detlMap.get(matUniqueKey);
+                detls.add(orderDetl);
+                detlMap.put(matUniqueKey, detls);
+            } else {
+                List<OrderDetl> detls = new ArrayList<>();
+                detls.add(orderDetl);
+                detlMap.put(matUniqueKey, detls);
+            }
+        }
+
+        List<OrderOutMergeDto> orderOutMergeDtos = new ArrayList<>();
+        for (OrderOutMergeParam param : filterParam) {
+            String matUniqueKey = Utils.getMatUniqueKey(param.getMatnr(), param.getBatch(), param.getFieldParams());
+            if (!detlMap.containsKey(matUniqueKey)) {
+                continue;
+            }
+
+            Double requireAnfme = param.getAnfme();
+
+            List<OrderDetl> orderDetlList = detlMap.get(matUniqueKey);
+            for (OrderDetl orderDetl : orderDetlList) {
+                orderDetl = orderDetlService.getById(orderDetl);
+                double issued = Optional.of(orderDetl.getAnfme() - orderDetl.getQty() - orderDetl.getWorkQty()).orElse(0.0D);
+                if (issued <= 0D) {
+                    continue;
+                }
+
+                OrderOutMergeDto orderOutMergeDto = new OrderOutMergeDto();
+                orderOutMergeDto.sync(param);
+                orderOutMergeDto.setOrderDetlId(orderDetl.getId());
+
+                Double updateWorkQty = null;
+
+                if (requireAnfme > issued) {
+                    orderOutMergeDto.setAnfme(issued);
+                    updateWorkQty = issued;
+                    requireAnfme -= issued;
+                } else {
+                    orderOutMergeDto.setAnfme(requireAnfme);
+                    updateWorkQty = requireAnfme;
+                    requireAnfme -= requireAnfme;
+                }
+
+                orderOutMergeDtos.add(orderOutMergeDto);
+
+                orderUtils.updateWorkQty(orderDetl.getId(), updateWorkQty);
+                if (requireAnfme <= 0) {
+                    break;
+                }
+            }
+        }
+
+        HashMap<Long, List<OrderOutMergeDto>> map = new HashMap<>();
+        for (OrderOutMergeDto orderOutMergeDto : orderOutMergeDtos) {
+            List<OrderOutMergeDto> list = null;
+            if (map.containsKey(orderOutMergeDto.getLocId())) {
+                list = map.get(orderOutMergeDto.getLocId());
+            } else {
+                list = new ArrayList<>();
+            }
+            list.add(orderOutMergeDto);
+            map.put(orderOutMergeDto.getLocId(), list);
+        }
+
+        List<TaskDetl> taskDetls = new ArrayList<>();
+        for (Map.Entry<Long, List<OrderOutMergeDto>> entry : map.entrySet()) {
+            Long locId = entry.getKey();
+            List<OrderOutMergeDto> list = entry.getValue();
+            Boolean all = outUtils.isAllForMerge(locId, list);
+            OrderOutMergeDto param = list.get(0);
+            Long operationPortId = param.getOperationPort();
+
+            Loc loc = locService.getById(locId);
+            if (loc == null) {
+                throw new CoolException("搴撲綅涓嶅瓨鍦�");
+            }
+
+            if (!loc.getLocStsId().equals(LocStsType.F.val())) {
+                throw new CoolException(loc.getLocNo() + "搴撲綅鐘舵�佸紓甯�");
+            }
+
+            OperationPort operationPort = operationPortService.getById(operationPortId);
+            if (operationPort == null) {
+                throw new CoolException("浣滀笟鍙d笉瀛樺湪");
+            }
+
+            long taskType = all ? 101L : 103L;
+
+            Task task = new Task();
+            task.setTaskNo(workService.generateTaskNo(taskType));
+            task.setTaskSts(TaskStsType.GENERATE_OUT.id);
+            task.setTaskType(taskType);
+            task.setIoPri(workService.generateIoPri(taskType));
+            task.setOriginLoc(loc.getLocNo());
+            task.setTargetSite(operationPort.getFlag());
+            task.setBarcode(loc.getBarcode());
+            boolean res = taskService.save(task);
+            if (!res) {
+                throw new CoolException("淇濆瓨宸ヤ綔妗eけ璐�");
+            }
+
+            for (OrderOutMergeDto merge : list) {
+                LocDetl locDetl = locDetlService.getById(merge.getLocDetlId());
+                if (locDetl == null) {
+                    throw new CoolException("鏄庣粏涓嶅瓨鍦�");
+                }
+
+                OrderDetl orderDetl = orderDetlService.getById(merge.getOrderDetlId());
+                if (orderDetl == null) {
+                    throw new CoolException("璁㈠崟鏄庣粏涓嶅瓨鍦�");
+                }
+
+                TaskDetl taskDetl = new TaskDetl();
+                taskDetl.sync(locDetl);
+                taskDetl.setId(null);
+                taskDetl.setTaskId(task.getId());
+                taskDetl.setTaskNo(task.getTaskNo());
+                taskDetl.setAnfme(merge.getAnfme());
+                taskDetl.setStock(locDetl.getAnfme());
+                taskDetl.setOrderId(orderDetl.getOrderId());
+                taskDetl.setOrderNo(orderDetl.getOrderNo());
+                taskDetl.setDetlId(orderDetl.getId());
+                if (!taskDetlService.save(taskDetl)) {
+                    throw new CoolException("淇濆瓨宸ヤ綔妗f槑缁嗗け璐�");
+                }
+
+                List<LocDetlField> locDetlFields = locDetlFieldService.list(new LambdaQueryWrapper<LocDetlField>().eq(LocDetlField::getDetlId, locDetl.getId()));
+                for (LocDetlField locDetlField : locDetlFields) {
+                    TaskDetlField taskDetlField = new TaskDetlField();
+                    taskDetlField.sync(locDetlField);
+                    taskDetlField.setId(null);
+                    taskDetlField.setDetlId(taskDetl.getId());
+                    boolean taskDetlFieldSave = taskDetlFieldService.save(taskDetlField);
+                    if (!taskDetlFieldSave) {
+                        throw new CoolException("鏄庣粏鎵╁睍鐢熸垚澶辫触");
+                    }
+                }
+
+                taskDetls.add(taskDetl);
+            }
+
+            //搴撲綅F => R
+            loc.setLocStsId(LocStsType.R.val());
+            loc.setUpdateTime(new Date());
+            boolean locUpdate = locService.updateById(loc);
+            if (!locUpdate) {
+                throw new CoolException("搴撲綅鐘舵�佹洿鏂板け璐�");
+            }
+
+        }
+
+    }
+
+
+    /**
+     * 娉㈡鐢熸垚鍑哄簱浠诲姟
+     * UTC鍑哄簱浠诲姟閫昏緫涓嶅彉锛屾坊鍔犲钩搴撳垽鍒�昏緫
+     * 1. 鑾峰彇娉㈡璁㈠崟鏄庣粏锛屽垽鍒槸鍚︿负骞冲簱璁㈠崟
+     * 2. 骞冲簱璁㈠崟鐢熸垚鎷h揣鍗曪紝 UTC璁㈠崟鐢熸垚鍑哄簱浠诲姟
+     * 3. 骞冲簱鍗曟嵁鏄庣粏鎵�鍗犲簱浣嶇墿鏂欐暟閲忓姞閿�
+     * 4. 鐢熸垚鍑哄簱鍗昉DA绔紝缁熶竴鍑哄簱鎵e噺搴撳瓨
+     * 5. 鐢熸垚鎷h揣鍗曞巻鍙叉。锛屽嚭搴撳崟鎹姞鍏ュ巻鍙叉。锛屽垹闄ゅ師鍗曟嵁
+     * 6. 鍒犻櫎娉㈡鍒楄〃鏁版嵁
+     *
+     * @param dto
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void orderOutMergeWave(OrderOutMergeParamDto dto) {
+        if (dto == null) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        if (dto.getWaveId() == null) {
+            throw new CoolException("鏈敓鎴愭尝娆�");
+        }
+
+        Wave wave = waveService.getById(dto.getWaveId());
+        if (Objects.isNull(wave)) {
+            throw new CoolException("娉㈡涓嶅瓨鍦�");
+        }
+
+        /**
+         * 娉㈡鍚堝苟鍑哄簱
+         * 1. 鍒ゆ柇鏄钩搴撹繕TCU搴�
+         * 2. 骞冲簱鐢熸垚鎷h揣鍗�
+         * 3. TCU搴撶敓鎴愪换鍔″崟
+         */
+        outStockByArea(dto, wave);
+
+        //娉㈡鐘舵�佷慨鏀逛负--鐢熸垚浠诲姟
+        wave.setWaveStatus(WaveStatusType.GENERATE.id);
+        wave.setUpdateTime(new Date());
+        if (!waveService.updateById(wave)) {
+            throw new CoolException("娉㈡鏇存柊澶辫触");
+        }
+    }
+
+    /**
+     * 1. 鍒ゆ柇褰撴尝娆″強搴撲綅鏄庣粏鏄惁瀛樺湪
+     * 2. 缁勫悎key-value(list)褰㈠紡鏁版嵁
+     *
+     * @param mergeParams
+     * @param wave
+     * @return
+     */
+    private Map<Long, List<OrderOutMergeDto>> checkLoc(List<OrderOutMergeParam> mergeParams, Wave wave) {
+        HashMap<String, Double> stockMap = new HashMap<>();
+        for (OrderOutMergeParam param : mergeParams) {
+            String matUniqueKey = Utils.getMatUniqueKey(param.getMatnr(), param.getBatch(), param.getFieldParams());
+            WaveDetl waveDetl = waveDetlService.getOne(new LambdaQueryWrapper<WaveDetl>().eq(WaveDetl::getStockIndex, matUniqueKey).eq(WaveDetl::getWaveId, wave.getId()));
+            if (waveDetl == null) {
+                throw new CoolException("娉㈡鏁版嵁涓嶅瓨鍦�");
+            }
+            //鑾峰彇褰撳墠闇�瑕佹墽琛屾暟閲�
+            double issued = Optional.of(waveDetl.getAnfme() - waveDetl.getWorkQty()).orElse(0.0D);
+            if (!stockMap.containsKey(matUniqueKey)) {
+                stockMap.put(matUniqueKey, issued);
+            }
+        }
+
+        HashMap<Long, List<OrderOutMergeDto>> map = new HashMap<>();
+        for (OrderOutMergeParam param : mergeParams) {
+            LocDetl locDetl = locDetlService.getById(param.getLocDetlId());
+            if (locDetl == null) {
+                continue;
+            }
+            //搴撲綅鏁伴噺灏忎簬鍑哄簱鏁伴噺 //鏂板workQty鐢ㄤ簬骞冲簱閿佸簱瀛�
+            if (locDetl.getAnfme() - locDetl.getWorkQty() - param.getAnfme() < 0) {
+                continue;
+            }
+
+            OrderOutMergeDto orderOutMergeDto = new OrderOutMergeDto();
+            orderOutMergeDto.sync(param);
+            //fixme 纭stockMap鏄惁鏈夌敤锛屾澶勫叆鍊煎悗鍗存病鏈変娇鐢�
+            String matUniqueKey = Utils.getMatUniqueKey(param.getMatnr(), param.getBatch(), param.getFieldParams());
+            Double issued = stockMap.get(matUniqueKey);
+            if (issued - orderOutMergeDto.getAnfme() < 0) {
+                orderOutMergeDto.setAnfme(issued);
+                issued = 0D;
+            } else {
+                issued -= orderOutMergeDto.getAnfme();
+            }
+
+            stockMap.put(matUniqueKey, issued);
+            //鏍规嵁搴撲綅鍋氬垎绫伙紝鍙娇鐢╯tream().groupby
+            List<OrderOutMergeDto> list = null;
+            if (map.containsKey(orderOutMergeDto.getLocId())) {
+                list = map.get(orderOutMergeDto.getLocId());
+            } else {
+                list = new ArrayList<>();
+            }
+
+            list.add(orderOutMergeDto);
+            map.put(orderOutMergeDto.getLocId(), list);
+        }
+
+        if (map.isEmpty()) {
+            throw new CoolException("搴撳瓨涓嶈冻");
+        }
+
+        return map;
+    }
+
+    /**
+     * 鏍规嵁涓嶅悓搴撲綅绫诲瀷鐢熸垚鍑哄簱鎷e崟鍙奀TU浠诲姟妗�
+     *
+     * @param dto
+     * @param wave
+     */
+    private void outStockByArea(OrderOutMergeParamDto dto, Wave wave) {
+        List<OrderOutMergeParam> params = dto.getList();
+        if (params.isEmpty()) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        //骞冲簱鏁版嵁婧�
+        List<OrderOutMergeParam> flatOrders = new ArrayList<>();// listMap.get(LocAreaTypeSts.LOC_AREA_TYPE_FLAT);
+        //TUC鏁版嵁婧�
+        List<OrderOutMergeParam> tucOrders = new ArrayList<>();//listMap.get(LocAreaTypeSts.LOC_AREA_TYPE_UTC);
+        //鎸夊簱浣嶇被鍨嬪垎绫�
+        //fixme 濡傛灉搴撳瓨涓嶈冻鏃讹紝鐢熸垚浠诲姟妗� 杩囨护鎺夋病鏈夊簱浣嶄俊鎭殑鏁版嵁銆傛壘鍚涙澃纭
+        List<OrderOutMergeParam> mergeParam = params.stream().filter(par -> {
+            return !StringUtils.isNullOrEmpty(par.getLocNo());
+        }).collect(Collectors.toList());
+        //鏁版嵁鍒嗙被 1.骞冲簱鏁版嵁  2. TUC鏁版嵁
+        Map<Long, List<OrderOutMergeParam>> listMap = mergeParam.stream().collect(Collectors.groupingBy(OrderOutMergeParam::getTypeId));
+
+        listMap.keySet().forEach(key -> {
+            if (key == LocAreaTypeSts.LOC_AREA_TYPE_FLAT.id) {
+                flatOrders.addAll(listMap.get(key));
+            } else {
+                tucOrders.addAll(listMap.get(key));
+            }
+        });
+        if (!flatOrders.isEmpty()) {
+            //骞冲簱鍑哄簱
+            outStockByFlat(flatOrders, wave);
+        }
+
+        if (!tucOrders.isEmpty()) {
+            //TUC鍑哄簱
+            outStockByTUC(tucOrders, wave);
+        }
+
+
+    }
+
+    /**
+     * TUC鍑哄簱--鐢熸垚鍑哄簱浠诲姟妗�
+     *
+     * @param tucOrders
+     * @param wave
+     */
+    private void outStockByTUC(List<OrderOutMergeParam> tucOrders, Wave wave) {//123
+        Map<Long, List<OrderOutMergeDto>> map = checkLoc(tucOrders, wave);
+
+        for (Map.Entry<Long, List<OrderOutMergeDto>> entry : map.entrySet()) {
+            Long locId = entry.getKey();
+            List<OrderOutMergeDto> list = entry.getValue();
+            //鍒ゆ柇鏄惁鍏ㄤ粨鍑哄簱
+            Boolean all = outUtils.isAllForMerge(locId, list);
+            OrderOutMergeDto param = list.get(0);
+            Long operationPortId = param.getOperationPort();
+
+            Loc loc = locService.getById(locId);
+            if (loc == null) {
+                throw new CoolException("搴撲綅涓嶅瓨鍦�");
+            }
+
+            if (!loc.getLocStsId().equals(LocStsType.F.val())) {
+                throw new CoolException(loc.getLocNo() + "搴撲綅鐘舵�佸紓甯�");
+            }
+
+            OperationPort operationPort = operationPortService.getById(operationPortId);
+            if (operationPort == null) {
+                throw new CoolException("浣滀笟鍙d笉瀛樺湪");
+            }
+            //101 鍏ㄦ嫋鍑哄簱   103 鎷h揣鍑哄簱
+            long taskType = all ? 101L : 103L;
+
+            Task task = new Task();
+            task.setTaskNo(workService.generateTaskNo(taskType));
+            task.setTaskSts(TaskStsType.GENERATE_OUT.id);
+            task.setTaskType(taskType);
+            task.setIoPri(workService.generateIoPri(taskType));
+            task.setOriginLoc(loc.getLocNo());
+            task.setTargetSite(operationPort.getFlag());
+            task.setBarcode(loc.getBarcode());
+            boolean res = taskService.save(task);
+            if (!res) {
+                throw new CoolException("淇濆瓨宸ヤ綔妗eけ璐�");
+            }
+
+            for (OrderOutMergeDto merge : list) {
+                LocDetl locDetl = locDetlService.getById(merge.getLocDetlId());
+                if (locDetl == null) {
+                    throw new CoolException("鏄庣粏涓嶅瓨鍦�");
+                }
+
+                TaskDetl taskDetl = new TaskDetl();
+                taskDetl.sync(locDetl);
+                taskDetl.setId(null);
+                taskDetl.setTaskId(task.getId());
+                taskDetl.setTaskNo(task.getTaskNo());
+                taskDetl.setAnfme(merge.getAnfme());
+                taskDetl.setStock(locDetl.getAnfme());
+                taskDetl.setWaveId(wave.getId());
+                taskDetl.setWaveNo(wave.getWaveNo());
+                taskDetl.setOrderId(null);
+                taskDetl.setOrderNo(null);
+                if (!taskDetlService.save(taskDetl)) {
+                    throw new CoolException("淇濆瓨宸ヤ綔妗f槑缁嗗け璐�");
+                }
+
+                List<LocDetlField> locDetlFields = locDetlFieldService.list(new LambdaQueryWrapper<LocDetlField>().eq(LocDetlField::getDetlId, locDetl.getId()));
+                for (LocDetlField locDetlField : locDetlFields) {
+                    TaskDetlField taskDetlField = new TaskDetlField();
+                    taskDetlField.sync(locDetlField);
+                    taskDetlField.setId(null);
+                    taskDetlField.setDetlId(taskDetl.getId());
+                    boolean taskDetlFieldSave = taskDetlFieldService.save(taskDetlField);
+                    if (!taskDetlFieldSave) {
+                        throw new CoolException("鏄庣粏鎵╁睍鐢熸垚澶辫触");
+                    }
+                }
+
+                String matUniqueKey = Utils.getMatUniqueKey(taskDetl.getMatnr(), taskDetl.getBatch(), taskDetl.getUniqueField());
+                WaveDetl waveDetl = waveDetlService.getOne(new LambdaQueryWrapper<WaveDetl>().eq(WaveDetl::getStockIndex, matUniqueKey).eq(WaveDetl::getWaveId, wave.getId()));
+                if (waveDetl == null) {
+                    throw new CoolException("娉㈡鏁版嵁涓嶅瓨鍦�");
+                }
+                waveDetl.setWorkQty(waveDetl.getWorkQty() + taskDetl.getAnfme());
+                waveDetl.setUpdateTime(new Date());
+                if (!waveDetlService.updateById(waveDetl)) {
+                    throw new CoolException("娉㈡鏁版嵁鏇存柊澶辫触");
+                }
+            }
+
+            //搴撲綅F => R
+            loc.setLocStsId(LocStsType.R.val());
+            loc.setUpdateTime(new Date());
+            boolean locUpdate = locService.updateById(loc);
+            if (!locUpdate) {
+                throw new CoolException("搴撲綅鐘舵�佹洿鏂板け璐�");
+            }
+        }
+    }
+
+    /**
+     * 骞冲簱鍑哄簱--鐢熸垚鍑哄簱鎷h揣鍗�
+     * 1. 鍒ゆ柇褰撳墠搴撲綅鏄惁瀛樺湪
+     * 2. 涓�寮犲崟鎹竴涓尝娆�
+     * 3. 涓�涓尝娆″鏉¤鍗�
+     * 4. 涓�涓簱浣嶅彲澶氭潯鏄庣粏
+     * 5. 鎷h揣鍗曞畬鎴愬悗锛岄噴鏀惧簱浣嶆槑缁嗛攣瀹氭暟閲�
+     *
+     * @param flatOrders
+     * @param wave
+     */
+    private void outStockByFlat(List<OrderOutMergeParam> flatOrders, Wave wave) {
+        //鏍¢獙搴撳瓨鏁伴噺
+        Map<Long, List<OrderOutMergeDto>> map = checkLoc(flatOrders, wave);
+        //鐢熸垚鎷h揣鍗�
+        PickSheet pickSheet = new PickSheet();
+        //娉㈡鏁伴噺姹囨��
+        double sum = flatOrders.stream().mapToDouble(OrderOutMergeParam::getAnfme).sum();
+        //鐢熸垚鎷h揣鍗曞彿
+        String pickNo = generatePickNO();
+        pickSheet.setId(null)
+                .setPickNo(pickNo)
+                .setMemo(wave.getMemo())
+                .setAnfme(sum)
+                .setWaveId(wave.getId())
+                .setWaveNo(wave.getWaveNo());
+
+        if (!pickSheetService.save(pickSheet)) {
+            throw new CoolException("鎷h揣鍗曞啓鍏ュけ璐ワ紒锛�");
+        }
+
+        //鏍规嵁搴撲綅ID鍒嗙粍
+        Map<Long, List<OrderOutMergeParam>> listMap = flatOrders.stream().collect(Collectors.groupingBy(OrderOutMergeParam::getLocId));
+        //鐢熸垚鎷h揣鏄庣粏
+        listMap.keySet().forEach(key -> {
+            Loc curLoc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getId, key));
+            if (Objects.isNull(curLoc)) {
+                throw new CoolException("涓婚敭." + key + "鐨勫簱浣嶄笉瀛樺湪锛侊紒");
+            }
+            listMap.get(key).forEach(outOder -> {
+                //鑾峰彇搴撲綅鏄庣粏淇℃伅
+                LocDetl locDetl = locDetlService.getOne(new LambdaQueryWrapper<LocDetl>().eq(LocDetl::getId, outOder.getLocDetlId()));
+                PickSheetDetl sheetDetl = new PickSheetDetl();
+                BeanUtils.copyProperties(outOder, sheetDetl);
+                //鑾峰彇鐗╂枡淇℃伅
+                Mat mat = matService.getOne(new LambdaQueryWrapper<Mat>().eq(Mat::getMatnr, outOder.getMatnr()));
+                //鎷h揣鍗曟槑缁�
+                sheetDetl.setBarcode(curLoc.getBarcode())
+                        .setPickId(pickSheet.getId())
+                        .setAnfme(BigDecimal.valueOf(outOder.getAnfme()))
+                        .setLocDetlId(locDetl.getId())
+                        .setMaktx(mat.getMaktx())
+                        .setMatId(mat.getId());
+                if (!pickSheetDetlService.save(sheetDetl)) {
+                    throw new CoolException("鎷h揣鏄庣粏鍒楁柊澶辫触");
+                }
+                //閿佸畾搴撳瓨閲�
+                locDetl.setWorkQty(locDetl.getWorkQty() + outOder.getAnfme());
+
+            });
+
+        });
+
+    }
+
+    /**
+     * 鐢熸垚鎷h揣鍗曞彿
+     *
+     * @return
+     */
+    private String generatePickNO() {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+        String format = simpleDateFormat.format(new Date());
+        Random random = new Random();
+        return "PN" + format + random.nextInt(10000);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void generateWave(GenerateWaveParam param) {
+        if (param == null) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        List<String> channels = param.getChannels();
+        if (channels == null) {
+            throw new CoolException("閫氶亾鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        if (channels.isEmpty()) {
+            throw new CoolException("閫氶亾鍙傛暟涓嶈兘涓虹┖");
+        }
+
+//        for (String channel : channels) {
+//            long count = cacheSiteService.count(new LambdaQueryWrapper<CacheSite>().eq(CacheSite::getChannel, channel).ne(CacheSite::getSiteStatus, 0));
+//            if (count > 0) {
+//                throw new CoolException(channel + "閫氶亾宸茬粡鍒嗛厤娉㈡");
+//            }
+//        }
+
+
+        List<Long> orderIds = param.getOrderIds();
+        if (orderIds == null) {
+            throw new CoolException("璁㈠崟鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        if (orderIds.isEmpty()) {
+            throw new CoolException("璁㈠崟鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        List<Order> orderList = orderService.listByIds(orderIds);
+        if (orderList.isEmpty()) {
+            throw new CoolException("璁㈠崟涓嶅瓨鍦�");
+        }
+
+        for (Order order : orderList) {
+            if (order.getWaveId() != null) {
+                throw new CoolException("褰撳墠璁㈠崟涓凡缁忕敓鎴愭尝娆�");
+            }
+        }
+
+        String waveNo = orderNoRuleService.getOrderNo(3);
+        Wave wave = new Wave();
+        wave.setWaveNo(waveNo);
+        wave.setWaveType(0);
+        wave.setWaveStatus(WaveStatusType.INIT.id);
+        if (!waveService.save(wave)) {
+            throw new CoolException("娉㈡鐢熸垚澶辫触");
+        }
+
+        HashMap<String, List<OrderDetl>> map = new HashMap<>();
+        for (Order order : orderList) {
+            List<OrderDetl> orderDetls = orderDetlService.list(new LambdaQueryWrapper<OrderDetl>().eq(OrderDetl::getOrderId, order.getId()));
+            for (OrderDetl orderDetl : orderDetls) {
+                List<OrderDetl> list = map.get(orderDetl.getStockIndex());
+                if (list == null) {
+                    list = new ArrayList<>();
+                }
+                list.add(orderDetl);
+                map.put(orderDetl.getStockIndex(), list);
+            }
+
+            order.setOrderSettle(OrderSettleType.WAVE.val());
+            order.setWaveId(wave.getId());
+            order.setWaveNo(waveNo);
+            order.setHasWave(1);
+            order.setUpdateTime(new Date());
+            if (!orderService.updateById(order)) {
+                throw new CoolException("璁㈠崟鍙嶅啓娉㈡澶辫触");
+            }
+
+//            List<CacheSite> cacheSites = cacheSiteService.list(new LambdaQueryWrapper<CacheSite>().eq(CacheSite::getSiteStatus, CacheSiteStatusType.O.id).in(CacheSite::getChannel, channels).orderBy(true, true, CacheSite::getChannel));
+//            if (cacheSites.isEmpty()) {
+//                throw new CoolException("缂撳瓨绔欑┖闂翠笉瓒筹紝璇风◢鍚庡啀璇�");
+//            }
+//
+//            CacheSite cacheSite = cacheSites.get(0);
+//            cacheSite.setOrderId(order.getId());
+//            cacheSite.setOrderNo(order.getOrderNo());
+//            cacheSite.setSiteStatus(CacheSiteStatusType.R.id);
+//            cacheSite.setUpdateTime(new Date());
+//            if (!cacheSiteService.updateById(cacheSite)) {
+//                throw new CoolException("缂撳瓨绔欐洿鏂板け璐�");
+//            }
+        }
+
+        for (Map.Entry<String, List<OrderDetl>> entry : map.entrySet()) {
+            String stockIndex = entry.getKey();
+            List<OrderDetl> orderDetls = entry.getValue();
+            Double anfme = 0D;
+            Long matId = null;
+            String matnr = null;
+            String batch = null;
+            List<FieldParam> uniqueField = null;
+            for (OrderDetl orderDetl : orderDetls) {
+                anfme += orderDetl.getAnfme();
+                matId = orderDetl.getMatId();
+                matnr = orderDetl.getMat$().getMatnr();
+                batch = orderDetl.getBatch();
+                uniqueField = orderDetl.getUniqueField();
+            }
+
+            WaveDetl waveDetl = new WaveDetl();
+            waveDetl.setWaveNo(waveNo);
+            waveDetl.setWaveId(wave.getId());
+            waveDetl.setStockIndex(stockIndex);
+            waveDetl.setMatId(matId);
+            waveDetl.setMatnr(matnr);
+            waveDetl.setBatch(batch);
+            waveDetl.setAnfme(anfme);
+            waveDetl.setWorkQty(0D);
+            waveDetl.setFieldParams(JSON.toJSONString(uniqueField));
+            if (!waveDetlService.save(waveDetl)) {
+                throw new CoolException("娉㈡鏄庣粏鐢熸垚澶辫触");
+            }
+
+        }
+
+    }
+
+    @Transactional
+    public void cancelWave(List<Long> waveIds) {
+        if (waveIds == null) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        if (waveIds.isEmpty()) {
+            throw new CoolException("鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        List<Wave> waves = waveService.listByIds(waveIds);
+        if (waves.isEmpty()) {
+            throw new CoolException("娉㈡涓嶅瓨鍦�");
+        }
+
+        for (Wave wave : waves) {
+            List<WaveDetl> waveDetls = waveDetlService.list(new LambdaQueryWrapper<WaveDetl>().eq(WaveDetl::getWaveId, wave.getId()));
+            for (WaveDetl waveDetl : waveDetls) {
+                long count = taskDetlService.count(new LambdaQueryWrapper<TaskDetl>().eq(TaskDetl::getWaveId, wave.getId()));
+                if (count > 0) {
+                    throw new CoolException("宸插瓨鍦ㄤ换鍔★紝绂佹鍙栨秷娉㈡");
+                }
+
+                List<Order> orders = orderService.list(new LambdaQueryWrapper<Order>().eq(Order::getWaveId, wave.getId()));
+                for (Order order : orders) {
+                    order.setWaveId(null);
+                    order.setWaveNo(null);
+                    order.setHasWave(0);
+                    if (order.getOrderSettle().equals(OrderSettleType.WAVE.val())) {
+                        order.setOrderSettle(OrderSettleType.WAIT.val());
+                    }
+                    if (!orderService.updateById(order)) {
+                        throw new CoolException("璁㈠崟鍙嶅啓澶辫触");
+                    }
+
+                    CacheSite cacheSite = cacheSiteService.getOne(new LambdaQueryWrapper<CacheSite>().eq(CacheSite::getOrderId, order.getId()));
+                    if (cacheSite == null) {
+                        throw new CoolException("缂撳瓨绔欎笉瀛樺湪");
+                    }
+                    cacheSite.setSiteStatus(CacheSiteStatusType.O.id);
+                    cacheSite.setOrderId(null);
+                    cacheSite.setOrderNo(null);
+                    cacheSite.setUpdateTime(new Date());
+                    if (!cacheSiteService.updateById(cacheSite)) {
+                        throw new CoolException("缂撳瓨绔欐竻绌哄け璐�");
+                    }
+                }
+
+                waveDetlService.removeById(waveDetl.getId());
+            }
+
+            waveService.removeById(wave.getId());
+        }
+
+    }
+
+}

--
Gitblit v1.9.1