From 225f9914090016cbe0836a06fbb852da05333504 Mon Sep 17 00:00:00 2001
From: cl <1442464845@qq.com>
Date: 星期六, 09 五月 2026 22:51:16 +0800
Subject: [PATCH] 日志优化

---
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java |  510 +++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 406 insertions(+), 104 deletions(-)

diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
index 91e0d70..34d50cb 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
@@ -1,12 +1,14 @@
 package com.vincent.rsf.server.manager.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.vincent.rsf.framework.exception.CoolException;
 import com.vincent.rsf.server.api.controller.erp.params.TaskInParam;
 import com.vincent.rsf.server.api.entity.dto.InTaskMsgDto;
 import com.vincent.rsf.server.api.service.WcsService;
 import com.vincent.rsf.server.api.utils.LocUtils;
 import com.vincent.rsf.server.common.constant.Constants;
+import com.vincent.rsf.server.common.utils.QuantityUtils;
 import com.vincent.rsf.server.manager.controller.params.CheckLocQueryParams;
 import com.vincent.rsf.server.manager.controller.params.LocToTaskParams;
 import com.vincent.rsf.server.manager.entity.*;
@@ -14,7 +16,9 @@
 import com.vincent.rsf.server.manager.mapper.LocItemMapper;
 import com.vincent.rsf.server.manager.service.*;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.vincent.rsf.server.system.constant.GlobalConfigCode;
 import com.vincent.rsf.server.system.constant.SerialRuleCode;
+import com.vincent.rsf.server.system.service.ConfigService;
 import com.vincent.rsf.server.system.utils.SerialRuleUtils;
 import lombok.Synchronized;
 import org.apache.commons.lang3.StringUtils;
@@ -25,11 +29,23 @@
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.*;
 import java.util.stream.Collectors;
 
 @Service("locItemService")
 public class LocItemServiceImpl extends ServiceImpl<LocItemMapper, LocItem> implements LocItemService {
+
+    private static final BigDecimal FULL_OUT_QTY_TOLERANCE = new BigDecimal("0.000001");
+
+    /** 鍙笌 {@link TaskStsType#GENERATE_OUT}锝瀧@link TaskStsType#WAVE_SEED} 琛旀帴杩藉姞鏄庣粏鐨勫嚭搴撲换鍔$被鍨� */
+    private static final List<Integer> OUTBOUND_TASK_TYPES_FOR_APPEND = Arrays.asList(
+            TaskType.TASK_TYPE_OUT.type,
+            TaskType.TASK_TYPE_PICK_AGAIN_OUT.type,
+            TaskType.TASK_TYPE_MERGE_OUT.type,
+            TaskType.TASK_TYPE_CHECK_OUT.type
+    );
 
     Logger logger = LoggerFactory.getLogger(LocItemServiceImpl.class);
 
@@ -51,7 +67,86 @@
     private WaveService waveService;
     @Autowired
     private BasStationService basStationService;
+    @Autowired
+    private MatnrService matnrService;
+    @Autowired
+    private AsnOrderItemService asnOrderItemService;
+    @Autowired
+    private ConfigService configService;
+    /** 鍏ュ簱/鍑哄簱淇濆瓨鍓嶏細鑻ヨ鏍兼垨鍨嬪彿涓虹┖鍒欎粠鐗╂枡甯﹀嚭 */
+    private void fillSpecModelFromMatnr(LocItem item) {
+        if (item == null || item.getMatnrId() == null) {
+            return;
+        }
+        if (StringUtils.isNotBlank(item.getSpec()) && StringUtils.isNotBlank(item.getModel())) {
+            return;
+        }
+        Matnr matnr = matnrService.getById(item.getMatnrId());
+        if (matnr == null) {
+            return;
+        }
+        if (StringUtils.isBlank(item.getSpec())) {
+            item.setSpec(matnr.getSpec());
+        }
+        if (StringUtils.isBlank(item.getModel())) {
+            item.setModel(matnr.getModel());
+        }
+    }
 
+    @Override
+    public boolean save(LocItem entity) {
+        fillSpecModelFromMatnr(entity);
+        return super.save(entity);
+    }
+
+    @Override
+    public boolean saveBatch(Collection<LocItem> entityList) {
+        if (entityList != null) {
+            entityList.forEach(this::fillSpecModelFromMatnr);
+        }
+        return super.saveBatch(entityList);
+    }
+
+    @Override
+    public boolean saveBatch(Collection<LocItem> entityList, int batchSize) {
+        if (entityList != null) {
+            entityList.forEach(this::fillSpecModelFromMatnr);
+        }
+        return super.saveBatch(entityList, batchSize);
+    }
+
+    @Override
+    public void fillSpecModelFromMatnrForRecords(List<LocItem> records) {
+        if (records == null || records.isEmpty()) {
+            return;
+        }
+        Set<Long> matnrIds = new HashSet<>();
+        for (LocItem r : records) {
+            if (r.getMatnrId() != null && (StringUtils.isBlank(r.getSpec()) || StringUtils.isBlank(r.getModel()))) {
+                matnrIds.add(r.getMatnrId());
+            }
+        }
+        if (matnrIds.isEmpty()) {
+            return;
+        }
+        Map<Long, Matnr> matnrMap = matnrService.listByIds(matnrIds).stream()
+                .collect(Collectors.toMap(Matnr::getId, m -> m));
+        for (LocItem r : records) {
+            if (r.getMatnrId() == null) {
+                continue;
+            }
+            Matnr m = matnrMap.get(r.getMatnrId());
+            if (m == null) {
+                continue;
+            }
+            if (StringUtils.isBlank(r.getSpec())) {
+                r.setSpec(m.getSpec());
+            }
+            if (StringUtils.isBlank(r.getModel())) {
+                r.setModel(m.getModel());
+            }
+        }
+    }
 
     /**
      * 搴撳瓨鍑哄簱鐢熸垚鍑哄簱浠诲姟
@@ -65,14 +160,12 @@
     @Override
     @Synchronized
     @Transactional(rollbackFor = Exception.class)
-    public void generateTask(Short resouce, LocToTaskParams map, Long loginUserId) throws Exception {
-        if (Objects.isNull(map.getSiteNo())) {
-            throw new CoolException("绔欑偣涓嶈兘涓虹┖锛�");
-        }
+    public synchronized void generateTask(Short resouce, LocToTaskParams map, Long loginUserId) throws Exception {
+        // 鍑哄簱鍙f湭浼犳椂榛樿 1001
+        String siteNo = StringUtils.isNotBlank(map.getSiteNo()) ? map.getSiteNo() : "1001";
         if (Objects.isNull(map.getItems()) || map.getItems().isEmpty()) {
             throw new CoolException("鏄庣粏涓嶈兘涓虹┖锛�");
         }
-        String siteNo = map.getSiteNo();
         List<LocItem> items = map.getItems();
         Map<Long, List<LocItem>> listMap = items.stream().collect(Collectors.groupingBy(LocItem::getLocId));
         WkOrder order;
@@ -90,107 +183,200 @@
             order = new WkOrder();
         }
 
+        final boolean appendSameLocEnabled = isOutAppendSameLocTaskEnabled();
+
         listMap.keySet().forEach(key -> {
-            Task task = new Task();
             Loc loc = locService.getById(key);
             logger.info("搴撲綅锛�>{}", loc.getCode());
             if (Objects.isNull(loc)) {
                 throw new CoolException("鏁版嵁閿欒锛氭墍閫夊簱瀛樹俊鎭笉瀛樺湪锛侊紒");
             }
-            if (!loc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_F.type)) {
-                throw new CoolException("搴撲綅:" + loc.getCode() + ",涓嶅浜嶧.鍦ㄥ簱鐘舵�侊紝涓嶅彲鎵цR.鍑哄簱棰勭害鎿嶄綔锛侊紒");
+            if (appendSameLocEnabled) {
+                if (LocStsType.LOC_STS_TYPE_S.type.equals(loc.getUseStatus())) {
+                    throw new CoolException("搴撲綅:" + loc.getCode() + " 澶勪簬S.鍏ュ簱棰勭害锛岄』寰呮嫞鏂�/鐩樼偣鍏ュ簱鍥炲簱鑷矲.鍦ㄥ簱鍚庡啀涓嬪彂鍑哄簱浠诲姟锛侊紒");
+                }
+                if (!LocStsType.LOC_STS_TYPE_F.type.equals(loc.getUseStatus())
+                        && !LocStsType.LOC_STS_TYPE_R.type.equals(loc.getUseStatus())) {
+                    throw new CoolException("搴撲綅:" + loc.getCode() + ",涓嶅浜嶧.鍦ㄥ簱鎴朢.鍑哄簱棰勭害鐘舵�侊紝涓嶅彲鎵ц鍑哄簱鍒嗛厤锛侊紒");
+                }
+            } else {
+                if (!LocStsType.LOC_STS_TYPE_F.type.equals(loc.getUseStatus())) {
+                    throw new CoolException("搴撲綅:" + loc.getCode() + " 涓嶅浜嶧.鍦ㄥ簱鐘舵�侊紝涓嶅彲鎵ц鍑哄簱鍒嗛厤锛侊紒");
+                }
             }
 
-            loc.setUseStatus(LocStsType.LOC_STS_TYPE_R.type);
-
-            if (!locService.updateById(loc)) {
-                throw new CoolException("搴撲綅鐘舵�佹洿鏂板け璐ワ紒锛�");
+            final boolean startedAsReserved = LocStsType.LOC_STS_TYPE_R.type.equals(loc.getUseStatus());
+            if (LocStsType.LOC_STS_TYPE_F.type.equals(loc.getUseStatus())) {
+                loc.setUseStatus(LocStsType.LOC_STS_TYPE_R.type);
+                if (!locService.updateById(loc)) {
+                    throw new CoolException("搴撲綅鐘舵�佹洿鏂板け璐ワ紒锛�");
+                }
             }
+
+            List<Task> openOutboundOnLoc = taskService.list(new LambdaQueryWrapper<Task>()
+                    .eq(Task::getOrgLoc, loc.getCode())
+                    .in(Task::getTaskType, OUTBOUND_TASK_TYPES_FOR_APPEND)
+                    .ge(Task::getTaskStatus, TaskStsType.GENERATE_OUT.id)
+                    .le(Task::getTaskStatus, TaskStsType.WAVE_SEED.id));
+
+            boolean reuseExistingTask = false;
+            Task task = null;
+            if (appendSameLocEnabled && startedAsReserved) {
+                if (openOutboundOnLoc.size() > 1) {
+                    throw new CoolException("搴撲綅:" + loc.getCode() + " 鍑哄簱棰勭害涓嬪瓨鍦ㄥ绗旀湭瀹岀粨鍑哄簱浠诲姟锛屼笉鍏佽鍐嶇敓鎴愪换鍔★紝璇峰緟鎷f枡鍥炲簱鑷矲鍚庡啀鍒嗛厤锛侊紒");
+                }
+                if (openOutboundOnLoc.isEmpty()) {
+                    throw new CoolException("搴撲綅:" + loc.getCode() + " 涓篟.鍑哄簱棰勭害浣嗘湭鎵惧埌鏈畬缁撳嚭搴撲换鍔★紝搴撲綅鏁版嵁寮傚父锛屼笉鍙笅鍙戝嚭搴撴垨娉㈡锛侊紒");
+                }
+                task = openOutboundOnLoc.get(0);
+                reuseExistingTask = true;
+                if (StringUtils.isNotBlank(task.getTargSite())
+                        && !StringUtils.equals(StringUtils.trimToEmpty(siteNo), StringUtils.trimToEmpty(task.getTargSite()))) {
+                    throw new CoolException("搴撲綅:" + loc.getCode() + " 宸叉湁鍑哄簱浠诲姟鐩爣绔欑偣涓�" + task.getTargSite() + "锛屼笌鏈绔欑偣涓嶄竴鑷达紝涓嶅彲杩藉姞鏄庣粏锛侊紒");
+                }
+            }
+
+            Map<String, Double> allocatedByKey = new HashMap<>();
+            for (Task t : openOutboundOnLoc) {
+                List<TaskItem> existItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, t.getId()));
+                for (TaskItem ti : existItems) {
+                    String k = buildAllocKey(ti.getMatnrId(), ti.getBatch(), ti.getFieldsIndex());
+                    allocatedByKey.put(k, allocatedByKey.getOrDefault(k, 0.0) + (ti.getAnfme() != null ? ti.getAnfme() : 0.0));
+                }
+            }
+
+            String barcodeToUse = StringUtils.isNotBlank(loc.getBarcode()) ? loc.getBarcode() : null;
+            if (barcodeToUse == null && !openOutboundOnLoc.isEmpty()) {
+                barcodeToUse = openOutboundOnLoc.get(0).getBarcode();
+                if (StringUtils.isNotBlank(barcodeToUse)) {
+                    Task refTask = openOutboundOnLoc.get(0);
+                    LambdaUpdateWrapper<Loc> locUw = new LambdaUpdateWrapper<Loc>().eq(Loc::getId, loc.getId())
+                            .set(Loc::getBarcode, barcodeToUse)
+                            .set(Loc::getUpdateBy, loginUserId)
+                            .set(Loc::getUpdateTime, new Date());
+                    if (refTask.getWeight() != null) {
+                        locUw.set(Loc::getWeight, refTask.getWeight());
+                    }
+                    locService.update(locUw);
+                }
+            }
+            if (barcodeToUse == null) {
+                List<LocItem> allocItems = listMap.get(key);
+                if (allocItems != null) {
+                    barcodeToUse = allocItems.stream()
+                            .map(LocItem::getBarcode)
+                            .filter(StringUtils::isNotBlank)
+                            .findFirst()
+                            .orElse(null);
+                }
+            }
+            if (barcodeToUse == null) {
+                barcodeToUse = loc.getBarcode();
+            }
+
             Task moveTask = new Task();
-            String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TASK_CODE, null);
-            task.setOrgLoc(loc.getCode())
-                    .setTaskCode(ruleCode)
-                    .setResource(resouce)
-                    .setTargSite(siteNo)
-                    .setSort(Constants.TASK_SORT_DEFAULT_VALUE)
-                    .setUpdateBy(loginUserId)
-                    .setCreateBy(loginUserId)
-                    .setCreateTime(new Date())
-                    .setUpdateTime(new Date())
-                    .setTaskStatus(TaskStsType.GENERATE_OUT.id)
-                    .setBarcode(loc.getBarcode())
-                    .setMemo(map.getMemo());
+            if (!reuseExistingTask) {
+                task = new Task();
+                String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TASK_CODE, null);
+                task.setOrgLoc(loc.getCode())
+                        .setTaskCode(ruleCode)
+                        .setResource(resouce)
+                        .setTargSite(siteNo)
+                        .setSort(Constants.TASK_SORT_DEFAULT_VALUE)
+                        .setUpdateBy(loginUserId)
+                        .setCreateBy(loginUserId)
+                        .setCreateTime(new Date())
+                        .setUpdateTime(new Date())
+                        .setTaskStatus(TaskStsType.GENERATE_OUT.id)
+                        .setBarcode(barcodeToUse)
+                        .setMemo(map.getMemo());
 
-            List<LocItem> locItems = this.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, key));
-            if (locItems.isEmpty()) {
-                throw new CoolException("鏁版嵁閿欒锛氭墍閫夊簱瀛樻槑缁嗕笉瀛樺湪锛侊紒");
-            }
+                List<LocItem> locItems = this.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, key));
+                if (locItems.isEmpty()) {
+                    throw new CoolException("鏁版嵁閿欒锛氭墍閫夊簱瀛樻槑缁嗕笉瀛樺湪锛侊紒");
+                }
 
-            Double orgQty = locItems.stream().mapToDouble(LocItem::getAnfme).sum();
-            List<LocItem> locItemList = listMap.get(key);
-            Double outQty = locItemList.stream().mapToDouble(LocItem::getOutQty).sum();
+                Double orgQty = locItems.stream().mapToDouble(LocItem::getAnfme).sum();
+                List<LocItem> locItemList = listMap.get(key);
+                Double outQty = locItemList.stream().mapToDouble(LocItem::getOutQty).sum();
+                BigDecimal orgQtyBd = BigDecimal.valueOf(orgQty).setScale(6, RoundingMode.HALF_UP);
+                BigDecimal outQtyBd = BigDecimal.valueOf(outQty).setScale(6, RoundingMode.HALF_UP);
 
-            if (map.getType().equals(Constants.TASK_TYPE_OUT_STOCK)
-                    || map.getType().equals(Constants.TASK_TYPE_ORDER_OUT_STOCK)
-                    || map.getType().equals(Constants.TASK_TYPE_WAVE_OUT_STOCK)) {
-                if (orgQty.compareTo(outQty) > 0) {
-                    //鎷f枡鍑哄簱 -- 鐩樼偣鍑哄簱
+                if (map.getType().equals(Constants.TASK_TYPE_OUT_STOCK)
+                        || map.getType().equals(Constants.TASK_TYPE_ORDER_OUT_STOCK)
+                        || map.getType().equals(Constants.TASK_TYPE_WAVE_OUT_STOCK)) {
+                    if (orgQtyBd.subtract(outQtyBd).compareTo(FULL_OUT_QTY_TOLERANCE) > 0) {
+                        DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
+                                .eq(DeviceSite::getSite, siteNo)
+                                .eq(!Objects.isNull(loc.getChannel()), DeviceSite::getChannel, loc.getChannel())
+                                .eq(DeviceSite::getType, TaskType.TASK_TYPE_PICK_AGAIN_OUT.type));
+                        if (Objects.isNull(deviceSite)) {
+                            throw new CoolException("绔欑偣涓嶆敮鎸佹嫞鏂欏嚭搴擄紒锛�");
+                        }
+                        task.setTaskType(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type).setWarehType(deviceSite.getDevice());
+                    } else {
+                        DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
+                                .eq(!Objects.isNull(loc.getChannel()), DeviceSite::getChannel, loc.getChannel())
+                                .eq(DeviceSite::getSite, siteNo).eq(DeviceSite::getType, TaskType.TASK_TYPE_OUT.type));
+                        if (Objects.isNull(deviceSite)) {
+                            throw new CoolException("绔欑偣涓嶆敮鎸佸叏鏉垮嚭搴擄紒锛�");
+                        }
+                        task.setTaskType(TaskType.TASK_TYPE_OUT.type).setWarehType(deviceSite.getDevice());
+
+                    }
+                } else if (map.getType().equals(Constants.TASK_TYPE_OUT_CHECK)) {
                     DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
+                            .eq(!Objects.isNull(loc.getChannel()), DeviceSite::getChannel, loc.getChannel())
                             .eq(DeviceSite::getSite, siteNo)
-                            .eq(DeviceSite::getChannel, loc.getChannel())
-                            .eq(DeviceSite::getType, TaskType.TASK_TYPE_PICK_AGAIN_OUT.type));
+                            .eq(DeviceSite::getType, TaskType.TASK_TYPE_CHECK_OUT.type));
                     if (Objects.isNull(deviceSite)) {
-                        throw new CoolException("绔欑偣涓嶆敮鎸佹嫞鏂欏嚭搴擄紒锛�");
+                        throw new CoolException("褰撳墠绔欑偣涓嶆敮鎸佺洏鐐瑰嚭搴擄紒锛�");
                     }
-                    task.setTaskType(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type).setWarehType(deviceSite.getDevice());
-                } else {
-                    //鍏ㄦ澘鍑哄簱
-                    DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
-                            .eq(DeviceSite::getChannel, loc.getChannel())
-                            .eq(DeviceSite::getSite, siteNo).eq(DeviceSite::getType, TaskType.TASK_TYPE_OUT.type));
-                    if (Objects.isNull(deviceSite)) {
-                        throw new CoolException("绔欑偣涓嶆敮鎸佸叏鏉垮嚭搴擄紒锛�");
-                    }
-                    task.setTaskType(TaskType.TASK_TYPE_OUT.type).setWarehType(deviceSite.getDevice());
+                    task.setTaskType(TaskType.TASK_TYPE_CHECK_OUT.type).setWarehType(deviceSite.getDevice());
+                }
 
+                if (!taskService.save(task)) {
+                    throw new CoolException("浠诲姟鍒涘缓澶辫触锛侊紒");
                 }
-            } else if (map.getType().equals(Constants.TASK_TYPE_OUT_CHECK)) {
-                //鐩樼偣鍑哄簱
-                DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
-                        .eq(!Objects.isNull(loc.getChannel()), DeviceSite::getChannel, loc.getChannel())
-                        .eq(DeviceSite::getSite, siteNo)
-                        .eq(DeviceSite::getType, TaskType.TASK_TYPE_CHECK_OUT.type));
-                if (Objects.isNull(deviceSite)) {
-                    throw new CoolException("褰撳墠绔欑偣涓嶆敮鎸佺洏鐐瑰嚭搴擄紒锛�");
+            } else {
+                if (StringUtils.isNotBlank(task.getBarcode()) && StringUtils.isBlank(barcodeToUse)) {
+                    barcodeToUse = task.getBarcode();
+                    LambdaUpdateWrapper<Loc> locUw = new LambdaUpdateWrapper<Loc>().eq(Loc::getId, loc.getId())
+                            .set(Loc::getBarcode, barcodeToUse)
+                            .set(Loc::getUpdateBy, loginUserId)
+                            .set(Loc::getUpdateTime, new Date());
+                    if (task.getWeight() != null) {
+                        locUw.set(Loc::getWeight, task.getWeight());
+                    }
+                    locService.update(locUw);
                 }
-                task.setTaskType(TaskType.TASK_TYPE_CHECK_OUT.type).setWarehType(deviceSite.getDevice());
+                List<LocItem> locItemsVerify = this.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, key));
+                if (locItemsVerify.isEmpty()) {
+                    throw new CoolException("鏁版嵁閿欒锛氭墍閫夊簱瀛樻槑缁嗕笉瀛樺湪锛侊紒");
+                }
             }
 
-            if (!taskService.save(task)) {
-                throw new CoolException("浠诲姟鍒涘缓澶辫触锛侊紒");
-            }
-
-            if (!LocUtils.isShallowLoc(loc.getCode())) {
-                //鑾峰彇娣卞簱浣嶅搴旀祬搴撲綅
-                String shallowLoc = LocUtils.getShallowLoc(loc.getCode());
-                Loc one = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, shallowLoc));
-                if (Objects.isNull(one)) {
-                    throw new CoolException("瀵瑰簲搴撲綅涓嶅瓨鍦紒锛�");
-                }
-                Task workTask = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, one.getBarcode()));
-                if (Objects.isNull(workTask)) {
-                    map.setOrgLoc(one.getCode());
-                    //浼樺厛鐢熸垚绉诲簱浠诲姟
-                    if (one.getUseStatus().equals(LocStsType.LOC_STS_TYPE_F.type)) {
-                        moveTask = genMoveTask(map, loginUserId);
-                    }
-                } else {
-                    workTask.setSort(task.getSort() + 1).setParentId(task.getId());
-                    if (!taskService.updateById(workTask)) {
-                        throw new CoolException("浼樺厛绾т慨鏀瑰け璐ワ紒锛�");
-                    }
-                }
-            }
+//            if (!LocUtils.isShallowLoc(loc.getCode())) {
+//                //鑾峰彇娣卞簱浣嶅搴旀祬搴撲綅
+//                String shallowLoc = LocUtils.getShallowLoc(loc.getCode());
+//                Loc one = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, shallowLoc));
+//                if (Objects.isNull(one)) {
+//                    throw new CoolException("瀵瑰簲搴撲綅涓嶅瓨鍦紒锛�");
+//                }
+//                Task workTask = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, one.getBarcode()));
+//                if (Objects.isNull(workTask)) {
+//                    map.setOrgLoc(one.getCode());
+//                    //浼樺厛鐢熸垚绉诲簱浠诲姟
+//                    if (one.getUseStatus().equals(LocStsType.LOC_STS_TYPE_F.type)) {
+//                        moveTask = genMoveTask(map, loginUserId);
+//                    }
+//                } else {
+//                    workTask.setSort(task.getSort() + 1).setParentId(task.getId());
+//                    if (!taskService.updateById(workTask)) {
+//                        throw new CoolException("浼樺厛绾т慨鏀瑰け璐ワ紒锛�");
+//                    }
+//                }
+//            }
 
             if (!Objects.isNull(moveTask.getId())) {
                 moveTask.setParentId(task.getId()).setSort(moveTask.getSort() + 1);
@@ -203,12 +389,37 @@
                 }
             }
 
+            final Task outTask = task;
+            if (outTask == null) {
+                throw new CoolException("浠诲姟鏁版嵁寮傚父锛侊紒");
+            }
+
             List<TaskItem> taskItems = new ArrayList<>();
             listMap.get(key).forEach(item -> {
+                LocItem locItem = locItemService.getById(item.getId());
+                if (Objects.isNull(locItem)) {
+                    throw new CoolException("搴撳瓨淇℃伅涓嶅瓨鍦紒");
+                }
+                if (item.getOutQty().compareTo(0.0) < 0) {
+                    throw new CoolException("鍑哄簱鏁伴噷涓嶈兘灏忎簬0锛侊紒");
+                }
+                Double allocQty = item.getOutQty();
+                String allocKey = buildAllocKey(locItem.getMatnrId(), locItem.getBatch(), locItem.getFieldsIndex());
+                Double already = allocatedByKey.getOrDefault(allocKey, 0.0);
+                Double available = Math.round((locItem.getAnfme() - already) * 1000000) / 1000000.0;
+                if (available.compareTo(0.0) <= 0) {
+                    throw new CoolException("搴撲綅:" + loc.getCode() + " 璇ョ墿鏂欏凡鏃犲墿浣欏彲鍒嗛厤鏁伴噺锛屼笉鍙啀杩藉姞璁㈠崟锛�");
+                }
+                if (allocQty.compareTo(available) > 0) {
+                    allocQty = available;
+                    item.setOutQty(allocQty);
+                }
+                allocatedByKey.put(allocKey, already + allocQty);
+
                 TaskItem taskItem = new TaskItem();
                 BeanUtils.copyProperties(item, taskItem);
-                taskItem.setTaskId(task.getId())
-                        .setAnfme(item.getOutQty())
+                taskItem.setTaskId(outTask.getId())
+                        .setAnfme(allocQty)
                         .setBatch(item.getBatch())
                         .setUpdateBy(loginUserId)
                         .setCreateBy(loginUserId)
@@ -216,34 +427,48 @@
                         .setUpdateTime(new Date())
                         .setOrderType(OrderType.ORDER_OUT.type);
                 if (map.getType().equals(Constants.TASK_TYPE_ORDER_OUT_STOCK)) {
-                    taskItem.setWkType(Short.parseShort(order.getWkType()))
+                    taskItem.setWkType(order.getWkType())
                             .setSourceCode(order.getCode())
-                            .setSourceId(order.getId());
+                            .setSourceId(order.getId())
+                            .setOrderId(order.getId())
+                            .setOrderItemId(item.getOrderItemId());
+                    String poOrCode = StringUtils.isNotBlank(order.getPoCode()) ? order.getPoCode() : order.getCode();
+                    if (StringUtils.isBlank(taskItem.getPlatOrderCode()) && StringUtils.isNotBlank(poOrCode)) {
+                        taskItem.setPlatOrderCode(poOrCode);
+                    }
+                    if (item.getOrderItemId() != null) {
+                        WkOrderItem oi = asnOrderItemService.getById(item.getOrderItemId());
+                        if (oi != null) {
+                            if (StringUtils.isBlank(taskItem.getPlatItemId()) && StringUtils.isNotBlank(oi.getPlatItemId())) {
+                                taskItem.setPlatItemId(oi.getPlatItemId());
+                            }
+                            if (StringUtils.isBlank(taskItem.getPlatWorkCode()) && StringUtils.isNotBlank(oi.getPlatWorkCode())) {
+                                taskItem.setPlatWorkCode(oi.getPlatWorkCode());
+                            }
+                            if (StringUtils.isBlank(taskItem.getPlatOrderCode())) {
+                                String p = StringUtils.isNotBlank(oi.getPlatOrderCode()) ? oi.getPlatOrderCode() : poOrCode;
+                                if (StringUtils.isNotBlank(p)) {
+                                    taskItem.setPlatOrderCode(p);
+                                }
+                            }
+                        }
+                    }
                 } else if (map.getType().equals(Constants.TASK_TYPE_WAVE_OUT_STOCK)) {
                     taskItem.setSourceId(wave.getId())
-                            .setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_OTHER.type))
+                            .setWkType(OrderWorkType.ORDER_WORK_TYPE_OTHER.type)
                             .setSourceCode(wave.getCode())
                             .setSource(item.getSource());
                 } else if (map.getType().equals(Constants.TASK_TYPE_OUT_CHECK) || map.getType().equals(Constants.TASK_TYPE_OUT_STOCK)) {
-                    taskItem.setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type))
+                    taskItem.setWkType(OrderWorkType.ORDER_WORK_TYPE_STOCK_OUT.type)
                             .setSource(item.getId())
                             .setSourceId(item.getLocId())
                             .setSourceCode(item.getLocCode());
                 }
                 taskItems.add(taskItem);
 
-                Double qty = Math.round((item.getWorkQty() + item.getOutQty()) * 10000) / 10000.0;
-                LocItem locItem = locItemService.getById(item.getId());
-                if (Objects.isNull(locItem)) {
-                    throw new CoolException("搴撳瓨淇℃伅涓嶅瓨鍦紒");
-                }
-
-                if (item.getOutQty().compareTo(0.0) < 0) {
-                    throw new CoolException("鍑哄簱鏁伴噷涓嶈兘灏忎簬0锛侊紒");
-                }
-
+                Double qty = Math.round((item.getWorkQty() != null ? item.getWorkQty() : 0.0) + allocQty) * 1000000.0 / 1000000.0;
                 if (locItem.getAnfme().compareTo(qty) < 0) {
-                    Double minusQty = Math.round((locItem.getAnfme() - locItem.getWorkQty()) * 10000) / 10000.0;
+                    Double minusQty = Math.round((locItem.getAnfme() - (locItem.getWorkQty() != null ? locItem.getWorkQty() : 0.0)) * 1000000) / 1000000.0;
                     item.setWorkQty(minusQty);
                 } else {
                     item.setWorkQty(qty);
@@ -257,6 +482,12 @@
 
             if (!taskItemService.saveBatch(taskItems)) {
                 throw new CoolException("浠诲姟鏄庣粏鐢熸垚澶辫触锛侊紒");
+            }
+            for (TaskItem ti : taskItems) {
+                if (ti.getAnfme() == null) {
+                    throw new CoolException("浠诲姟鏄庣粏鏁伴噺寮傚父");
+                }
+                taskService.enqueueCloudWmsOutNotifyLogEarly(outTask, ti, QuantityUtils.toScaledBigDecimal(ti.getAnfme()));
             }
         });
     }
@@ -294,7 +525,7 @@
             //鐩爣搴撲綅涓虹┖锛岃嚜鍔ㄨ幏鍙栨柊搴撲綅
             DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
                     .eq(DeviceSite::getType, TaskType.TASK_TYPE_LOC_MOVE.type)
-                    .eq(DeviceSite::getChannel, orgLoc.getChannel()), false);
+                    .eq(!Objects.isNull(orgLoc.getChannel()), DeviceSite::getChannel, orgLoc.getChannel()), false);
             if (Objects.isNull(deviceSite)) {
                 throw new CoolException("绔欑偣淇℃伅涓嶅瓨鍦紒锛�");
             }
@@ -320,7 +551,8 @@
             throw new CoolException("鐩爣搴撲綅涓嶅瓨鍦紒锛�");
         }
 
-        targetLoc.setUseStatus(LocStsType.LOC_STS_TYPE_S.type);
+        targetLoc.setUseStatus(LocStsType.LOC_STS_TYPE_S.type)
+                .setWeight(orgLoc.getWeight());
 
         if (!locService.updateById(targetLoc)) {
             throw new CoolException("鐩爣搴撲綅棰勭害澶辫触锛侊紒");
@@ -358,13 +590,73 @@
                         .setSource(item.getId())
                         .setUpdateTime(new Date())
                         .setOrderType(OrderType.ORDER_IN.type)
-                        .setWkType(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_OTHER_IN.type));
+                        .setWkType(OrderWorkType.ORDER_WORK_TYPE_OTHER_IN.type);
                 taskItems.add(taskItem);
             }
             if (!taskItemService.saveBatch(taskItems)) {
                 throw new CoolException("浠诲姟鏄庣粏鐢熸垚澶辫触锛侊紒");
             }
         }
+        return task;
+    }
+
+    /**
+     * 绌烘澘鍑哄簱锛氫粠鎸囧畾绌烘澘搴撲綅锛坲seStatus=D锛夌敓鎴� TASK_TYPE_EMPITY_OUT 浠诲姟鑷崇洰鏍囩珯鐐广��
+     * 闇�鍦ㄨ澶囩珯鐐逛腑閰嶇疆 type=110锛堢┖鏉垮嚭搴擄級鐨勭珯鐐硅矾寰勩��
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Task generateTaskEmpty(LocToTaskParams map, Long loginUserId) {
+        if (StringUtils.isBlank(map.getSiteNo())) {
+            throw new CoolException("鐩爣绔欑偣涓嶈兘涓虹┖锛�");
+        }
+        if (StringUtils.isBlank(map.getOrgLoc())) {
+            throw new CoolException("婧愬簱浣嶄笉鑳戒负绌猴紒");
+        }
+        if (!Constants.TASK_TYPE_OUT_STOCK_EMPTY.equals(map.getType())) {
+            throw new CoolException("绫诲瀷蹇呴』涓� empty锛堢┖鏉垮嚭搴擄級锛�");
+        }
+        Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, map.getOrgLoc()));
+        if (loc == null) {
+            throw new CoolException("婧愬簱浣嶄笉瀛樺湪锛�");
+        }
+        if (!LocStsType.LOC_STS_TYPE_D.type.equals(loc.getUseStatus())) {
+            throw new CoolException("搴撲綅 " + loc.getCode() + " 涓嶅浜庣┖鏉跨姸鎬侊紙D锛夛紝涓嶅彲鎵ц绌烘澘鍑哄簱锛�");
+        }
+        DeviceSite deviceSite = deviceSiteService.getOne(new LambdaQueryWrapper<DeviceSite>()
+                .eq(DeviceSite::getSite, map.getSiteNo())
+                .eq(DeviceSite::getType, TaskType.TASK_TYPE_EMPITY_OUT.type)
+                .last("limit 1"));
+        if (deviceSite == null) {
+            throw new CoolException("绔欑偣涓嶆敮鎸佺┖鏉垮嚭搴撴垨鏈厤缃┖鏉垮嚭搴撹矾寰勶紒");
+        }
+        if (!locService.update(new LambdaUpdateWrapper<Loc>()
+                .eq(Loc::getId, loc.getId())
+                .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_R.type))) {
+            throw new CoolException("搴撲綅鍑哄簱棰勭害澶辫触锛�");
+        }
+        String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_TASK_CODE, null);
+        if (StringUtils.isBlank(ruleCode)) {
+            throw new CoolException("缂栫爜閿欒锛氳纭鏄惁宸茬敓鎴愶紒");
+        }
+        Task task = new Task();
+        task.setTaskCode(ruleCode)
+                .setTaskStatus(TaskStsType.GENERATE_OUT.id)
+                .setTaskType(TaskType.TASK_TYPE_EMPITY_OUT.type)
+                .setWarehType(WarehType.WAREHOUSE_TYPE_CRN.val)
+                .setOrgLoc(loc.getCode())
+                .setTargSite(map.getSiteNo())
+                .setBarcode(loc.getBarcode())
+                .setSort(Constants.TASK_SORT_DEFAULT_VALUE)
+                .setCreateBy(loginUserId)
+                .setUpdateBy(loginUserId)
+                .setCreateTime(new Date())
+                .setUpdateTime(new Date())
+                .setMemo(map.getMemo());
+        if (!taskService.save(task)) {
+            throw new CoolException("绌烘澘鍑哄簱浠诲姟鍒涘缓澶辫触锛�");
+        }
+        logger.info("[绌烘澘鍑哄簱] 宸插垱寤轰换鍔�: {}, 婧愬簱浣�: {}, 鐩爣绔欑偣: {}", ruleCode, loc.getCode(), map.getSiteNo());
         return task;
     }
 
@@ -382,4 +674,14 @@
                 .in(!matnr.getMatnrCode().isEmpty(), LocItem::getMatnrCode, matnr.getMatnrCode());
         return  this.baseMapper.listByMatnr(LocStsType.LOC_STS_TYPE_F.type, matnr.getChannel(), wrapper);
     }
+
+    /** 搴撲綅宸插垎閰嶉噺鎸夌墿鏂�+鎵规+绁ㄥ彿鑱氬悎鐨� key */
+    private static String buildAllocKey(Long matnrId, String batch, String fieldsIndex) {
+        return (matnrId != null ? matnrId : "") + "|" + (batch != null ? batch : "") + "|" + (fieldsIndex != null ? fieldsIndex : "");
+    }
+
+    private boolean isOutAppendSameLocTaskEnabled() {
+        Boolean v = configService.getVal(GlobalConfigCode.OUT_APPEND_SAME_LOC_TASK_ENABLED, Boolean.class);
+        return Boolean.TRUE.equals(v);
+    }
 }

--
Gitblit v1.9.1