| package com.zy.asrs.wms.asrs.manage;  | 
|   | 
| import com.alibaba.fastjson.JSON;  | 
| 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.*;  | 
| import com.zy.asrs.wms.asrs.entity.dto.*;  | 
| import com.zy.asrs.wms.asrs.entity.enums.*;  | 
| import com.zy.asrs.wms.asrs.entity.param.*;  | 
| 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;  | 
|   | 
| /**  | 
|  * 出库管理  | 
|  */  | 
| @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("作业口不存在");  | 
|         }  | 
|   | 
|         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("保存工作档失败");  | 
|             }  | 
|             // 工作档明细保存  | 
|             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("保存工作档明细失败");  | 
|                 }  | 
|   | 
|                 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);  | 
| //            }  | 
| //        });  | 
|   | 
|         /**  | 
|          * 平库优先出库完成后,当订单明细workQty + 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("作业口不存在");  | 
|             }  | 
|   | 
|   | 
|             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("保存工作档失败");  | 
|             }  | 
|   | 
|             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("保存工作档明细失败");  | 
|                 }  | 
|   | 
|                 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 -> {  | 
|             if (pars.getStatus() == 1) {  | 
|                 return;  | 
|             }  | 
|             List<MergePreviewResultLocDto> locDtos = new ArrayList<>();  | 
|             MergePreviewResultDto resultDto = new MergePreviewResultDto();  | 
|             resultDto.sync(pars);  | 
|             resultDto.setOrderIds(pars.getOrderIds());  | 
|             //总需求数量  | 
|             resultDto.setAnfme(pars.getAnfme());  | 
|             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());  | 
|                     locDto.setAnfme(detl.getAnfme());  | 
|                     locDto.setWorkQty(detl.getWorkQty());  | 
|                     locDtos.add(locDto);  | 
|                     //库位实际可用数量  | 
|                     Double surplusQty = Math.round((detl.getAnfme() - detl.getWorkQty()) * 10000) / 10000.0;  | 
|                     if (surplusQty <= 0) {  | 
|                         continue;  | 
|                     }  | 
|                     //波次数量减去库位可用数量后,盈余数量  | 
|                     anfme = anfme - surplusQty;  | 
|                     if (anfme > 0) {  | 
|                         //当前可使用数量  | 
|                         resultDto.setFetchQty(surplusQty);  | 
|                         //余下需求数量  | 
|                         pars.setStatus(2);  | 
|                         pars.setWorkQty(pars.getWorkQty() + surplusQty);  | 
|                         pars.setAnfme(anfme);  | 
|                     } else {  | 
|                         //当前使用数量  | 
|                         resultDto.setFetchQty(pars.getAnfme());  | 
|                         //余下需求  | 
|                         pars.setWorkQty(pars.getWorkQty() + pars.getAnfme());  | 
|                         pars.setStatus(1);  | 
|                         pars.setAnfme(0.0);  | 
|                         break;  | 
|                     }  | 
|                 }  | 
|   | 
|                 if (!Objects.isNull(resultDto.getFetchQty()) && !(new BigDecimal(resultDto.getFetchQty()).compareTo(new BigDecimal("0.00")) == 0)) {  | 
|                     resultDto.setOtherLocs(new ArrayList<>());  | 
|   | 
|                     resultDto.setType(LocAreaTypeSts.LOC_AREA_TYPE_FLAT.desc);  | 
|   | 
|                     resultDtos.add(resultDto);  | 
|                 }  | 
|             }  | 
|         });  | 
|   | 
|         //平库查询完成后,再查询TCU  | 
|         for (MergePreviewDto dto : param) {  | 
|             //单据已完成,跳出  | 
|             if (dto.getStatus() == 1) {  | 
|                 continue;  | 
|             }  | 
| //            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.setType(LocAreaTypeSts.LOC_AREA_TYPE_UTC.desc);  | 
|                 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());  | 
|   | 
|             resultDto.setType(LocAreaTypeSts.LOC_AREA_TYPE_UTC.desc);  | 
|   | 
|             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("作业口不存在");  | 
|             }  | 
|   | 
|             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("保存工作档失败");  | 
|             }  | 
|   | 
|             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("保存工作档明细失败");  | 
|                 }  | 
|   | 
|                 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. 平库订单生成拣货单, UTC订单生成出库任务  | 
|      * 3. 平库单据明细所占库位物料数量加锁  | 
|      * 4. 生成出库单PDA端,统一出库扣减库存  | 
|      * 5. 生成拣货单历史档,出库单据加入历史档,删除原单据  | 
|      * 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. 判断是平库还CTU库  | 
|          * 2. 平库生成拣货单  | 
|          * 3. CTU库生成任务单  | 
|          */  | 
|         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);  | 
|             //根据库位做分类,可使用stream().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;  | 
|     }  | 
|   | 
|     /**  | 
|      * 根据不同库位类型生成出库拣货单或CTU任务档  | 
|      *  | 
|      * @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);  | 
|         //CTU数据源  | 
|         List<OrderOutMergeParam> tucOrders = new ArrayList<>();//listMap.get(LocAreaTypeSts.LOC_AREA_TYPE_UTC);  | 
|         //按库位类型分类  | 
|         List<OrderOutMergeParam> mergeParam = params.stream().filter(par -> {  | 
|             return !StringUtils.isNullOrEmpty(par.getLocNo());  | 
|         }).collect(Collectors.toList());  | 
|         //数据分类 1.平库数据  2. CTU数据  | 
|         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()) {  | 
|             //CTU出库  | 
|             outStockByTUC(tucOrders, wave);  | 
|         }  | 
|     }  | 
|   | 
|     /**  | 
|      * CTU出库--生成出库任务档  | 
|      *  | 
|      * @param tucOrders  | 
|      * @param wave  | 
|      */  | 
|     private void outStockByTUC(List<OrderOutMergeParam> tucOrders, Wave wave) {  | 
|         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("作业口不存在");  | 
|             }  | 
|             //101 全拖出库   103 拣货出库  | 
|             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("保存工作档失败");  | 
|             }  | 
|   | 
|             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("保存工作档明细失败");  | 
|                 }  | 
|   | 
|                 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("波次数据更新失败");  | 
|                 }  | 
|             }  | 
|   | 
|             List<Order> orders = orderService.list(new LambdaQueryWrapper<Order>().eq(Order::getWaveNo, wave.getWaveNo()));  | 
|             if (orders.isEmpty()) {  | 
|                 throw new CoolException("当前波次订单不存在!!");  | 
|             }  | 
|   | 
|             List<CacheSite> cacheSites = cacheSiteService.list(new LambdaQueryWrapper<CacheSite>()  | 
|                     .eq(CacheSite::getSiteStatus, CacheSiteStatusType.O.id).eq(CacheSite::getChannel,task.getTargetSite()));  | 
|   | 
|             if (cacheSites.isEmpty()) {  | 
|                 throw new CoolException("缓存站空间不足,请稍后再试");  | 
|             }  | 
|   | 
|             if (cacheSites.size() < orders.size()) {  | 
|                 throw new CoolException("缓存站空间不足,请稍后再试");  | 
|             }  | 
|   | 
|             for (int i = 0; i < orders.size(); i++) {  | 
|                 CacheSite cacheSite = cacheSites.get(i);  | 
|                 cacheSite.setOrderId(orders.get(i).getId());  | 
|                 cacheSite.setOrderNo(orders.get(i).getOrderNo());  | 
|                 cacheSite.setSiteStatus(CacheSiteStatusType.R.id);  | 
|                 cacheSite.setBarcode(loc.getBarcode());  | 
|                 cacheSite.setUpdateTime(new Date());  | 
|                 if (!cacheSiteService.updateById(cacheSite)) {  | 
|                     throw new CoolException("缓存站更新失败");  | 
|                 }  | 
|             }  | 
|   | 
|             //库位F => R  | 
|             loc.setLocStsId(LocStsType.R.val());  | 
|             loc.setUpdateTime(new Date());  | 
|             boolean locUpdate = locService.updateById(loc);  | 
|             if (!locUpdate) {  | 
|                 throw new CoolException("库位状态更新失败");  | 
|             }  | 
|         }  | 
|     }  | 
|   | 
|     /**  | 
|      * 平库出库--生成出库拣货单  | 
|      * 1. 判断当前库位是否存在  | 
|      * 2. 一张单据一个波次  | 
|      * 3. 一个波次多条订单  | 
|      * 4. 一个库位可多条明细  | 
|      * 5. 拣货单完成后,释放库位明细锁定数量  | 
|      *  | 
|      * @param flatOrders  | 
|      * @param wave  | 
|      */  | 
|     private void outStockByFlat(List<OrderOutMergeParam> flatOrders, Wave wave) {  | 
|         //校验库存数量  | 
|         Map<Long, List<OrderOutMergeDto>> map = checkLoc(flatOrders, wave);  | 
|         //生成拣货单  | 
|         PickSheet pickSheet = new PickSheet();  | 
|         //波次数量汇总  | 
|         double sum = flatOrders.stream().mapToDouble(OrderOutMergeParam::getAnfme).sum();  | 
|         //生成拣货单号  | 
|         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("拣货单写入失败!!");  | 
|         }  | 
|   | 
|         //根据库位ID分组  | 
|         Map<Long, List<OrderOutMergeParam>> listMap = flatOrders.stream().collect(Collectors.groupingBy(OrderOutMergeParam::getLocId));  | 
|         //生成拣货明细  | 
|         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()));  | 
|                 //拣货单明细  | 
|                 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("拣货明细列新失败");  | 
|                 }  | 
|                 //锁定库存量  | 
|                 locDetl.setWorkQty(locDetl.getWorkQty() + outOder.getAnfme());  | 
|   | 
|                 if (!locDetlService.updateById(locDetl)) {  | 
|                     throw new CoolException("库存加锁失败!!");  | 
|                 }  | 
|   | 
|             });  | 
|   | 
|         });  | 
|   | 
|     }  | 
|   | 
|     /**  | 
|      * 生成拣货单号  | 
|      *  | 
|      * @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(rollbackFor = Exception.class)  | 
|     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<PickSheet> pickSheets = pickSheetService.list(new LambdaQueryWrapper<PickSheet>()  | 
|                         .eq(PickSheet::getWaveNo, wave.getWaveNo())  | 
|                         .eq(PickSheet::getDeleted, 0)  | 
|                         .eq(PickSheet::getStatus, 1));  | 
|                 if (!pickSheets.isEmpty()) {  | 
|                     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) {  | 
|                         cacheSite.setSiteStatus(CacheSiteStatusType.O.id);  | 
|                         cacheSite.setOrderId(null);  | 
|                         cacheSite.setOrderNo(null);  | 
|                         cacheSite.setBarcode(null);  | 
|                         cacheSite.setUpdateTime(new Date());  | 
|                         if (!cacheSiteService.updateById(cacheSite)) {  | 
|                             throw new CoolException("缓存站清空失败");  | 
|                         }  | 
|                     }  | 
|                 }  | 
|   | 
|                 waveDetlService.removeById(waveDetl.getId());  | 
|             }  | 
|   | 
|             waveService.removeById(wave.getId());  | 
|         }  | 
|   | 
|     }  | 
|   | 
| }  |