From bb7dd1f513149ecd2887895c807861fdd06a43f6 Mon Sep 17 00:00:00 2001
From: chen.lin <1442464845@qq.com>
Date: 星期三, 11 二月 2026 15:29:27 +0800
Subject: [PATCH] 展示库存明细

---
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java |  364 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 323 insertions(+), 41 deletions(-)

diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
index c90f8a7..a42985b 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
@@ -8,17 +8,22 @@
 import com.vincent.rsf.framework.exception.CoolException;
 import com.vincent.rsf.server.api.utils.LocUtils;
 import com.vincent.rsf.server.common.constant.Constants;
+import com.vincent.rsf.server.common.domain.BaseParam;
+import com.vincent.rsf.server.common.domain.PageParam;
 import com.vincent.rsf.server.manager.controller.dto.ExistDto;
 import com.vincent.rsf.server.manager.controller.dto.OrderOutItemDto;
 import com.vincent.rsf.server.manager.controller.params.*;
 import com.vincent.rsf.server.manager.enums.*;
+import com.vincent.rsf.server.manager.entity.Matnr;
 import com.vincent.rsf.server.manager.entity.*;
 import com.vincent.rsf.server.manager.mapper.AsnOrderMapper;
+import com.vincent.rsf.server.manager.mapper.LocItemMapper;
 import com.vincent.rsf.server.manager.service.*;
 import com.vincent.rsf.server.manager.utils.LocManageUtil;
 import com.vincent.rsf.server.manager.utils.OptimalAlgorithmUtil;
 import com.vincent.rsf.server.system.constant.SerialRuleCode;
 import com.vincent.rsf.server.system.utils.SerialRuleUtils;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -28,6 +33,7 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -40,11 +46,14 @@
  * @return
  * @time 2025/3/7 08:02
  */
+@Slf4j
 @Service("outStockServiceImpl")
 public class OutStockServiceImpl extends ServiceImpl<AsnOrderMapper, WkOrder> implements OutStockService {
 
     public Logger logger = LoggerFactory.getLogger(this.getClass());
 
+    /** 鍑哄簱鍓╀綑閲忓宸細灏忎簬绛変簬姝ゅ�艰涓哄凡鍒嗛厤瀹岋紝閬垮厤娴偣璇樊浜х敓澶氫綑鈥滃簱瀛樹笉瓒斥�濊 */
+    private static final BigDecimal ISSUED_TOLERANCE = new BigDecimal("0.000001");
 
     @Autowired
     private AsnOrderItemService asnOrderItemService;
@@ -76,7 +85,73 @@
     private LocService locService;
     @Autowired
     private WaveOrderRelaServiceImpl waveOrderRelaService;
+    @Autowired
+    private TaskItemService taskItemService;
+    @Autowired
+    private LocItemMapper locItemMapper;
 
+    @Override
+    public PageParam<Matnr, BaseParam> pageMatnrForOutStock(PageParam<Matnr, BaseParam> pageParam, Map<String, Object> params) {
+        PageParam<Matnr, BaseParam> page = matnrService.getMatnrPage(pageParam, params);
+        List<Matnr> records = page.getRecords();
+        if (records == null || records.isEmpty()) {
+            return page;
+        }
+        List<Long> matnrIds = records.stream().map(Matnr::getId).collect(Collectors.toList());
+        String locUseStatus = params.get("locUseStatus") != null ? params.get("locUseStatus").toString() : null;
+        List<Map<String, Object>> stockList = locItemMapper.listStockByMatnrIds(matnrIds, locUseStatus);
+        Map<Long, Double> stockQtyMap = new HashMap<>();
+        Map<Long, String> locStatusDescMap = new HashMap<>();
+        Map<Long, String> locCodesMap = new HashMap<>();
+        for (Map<String, Object> row : stockList) {
+            Long matnrId = getLong(row, "matnrId", "matnrid");
+            if (matnrId == null) continue;
+            Object qty = getAny(row, "stockQty", "stockqty");
+            double v = qty instanceof Number ? ((Number) qty).doubleValue() : 0d;
+            stockQtyMap.put(matnrId, v);
+            String locCodes = getStr(row, "locCodes", "loccodes");
+            if (locCodes != null && !locCodes.isEmpty()) {
+                locCodesMap.put(matnrId, locCodes);
+            }
+            String locStatuses = getStr(row, "locStatuses", "locstatuses");
+            if (locStatuses != null && !locStatuses.isEmpty()) {
+                String desc = Arrays.stream(locStatuses.split(","))
+                        .map(String::trim)
+                        .map(LocStsType::getDescByType)
+                        .collect(Collectors.joining(","));
+                locStatusDescMap.put(matnrId, desc);
+            } else if (locUseStatus != null && !locUseStatus.isEmpty()) {
+                locStatusDescMap.put(matnrId, LocStsType.getDescByType(locUseStatus));
+            }
+        }
+        for (Matnr record : records) {
+            record.setStockQty(stockQtyMap.getOrDefault(record.getId(), 0d));
+            record.setLocUseStatus$(locStatusDescMap.get(record.getId()));
+            record.setLocCodes$(locCodesMap.get(record.getId()));
+        }
+        return page;
+    }
+
+    private static Long getLong(Map<String, Object> map, String... keys) {
+        Object v = getAny(map, keys);
+        if (v == null) return null;
+        if (v instanceof Long) return (Long) v;
+        if (v instanceof Number) return ((Number) v).longValue();
+        try { return Long.parseLong(v.toString()); } catch (NumberFormatException e) { return null; }
+    }
+
+    private static String getStr(Map<String, Object> map, String... keys) {
+        Object v = getAny(map, keys);
+        return v != null ? v.toString() : null;
+    }
+
+    private static Object getAny(Map<String, Object> map, String... keys) {
+        for (String key : keys) {
+            Object v = map.get(key);
+            if (v != null) return v;
+        }
+        return null;
+    }
 
     /**
      * @param
@@ -414,6 +489,7 @@
      * @time 2025/4/29 13:47
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public R updateOrderItem(AsnOrderAndItemsParams params, Long loginUserId) {
         WkOrder orders = params.getOrders();
         if (Objects.isNull(orders)) {
@@ -428,12 +504,102 @@
         if (Objects.isNull(params.getItems()) || params.getItems().isEmpty()) {
             throw new CoolException("鏄庣粏鍙傛暟涓嶈兘涓虹┖锛侊紒");
         }
+        // 鍒犻櫎/淇敼鏄庣粏鍓嶆敹闆嗗綋鍓嶅崟鎹笅鐨勬槑缁� id锛岀敤浜庢牎楠屼笌鍚屾搴撲綅鐘舵��
+        List<Long> existingIds = asnOrderItemService.list(
+                new LambdaQueryWrapper<WkOrderItem>().eq(WkOrderItem::getOrderId, orders.getId()))
+                .stream().map(WkOrderItem::getId).collect(Collectors.toList());
+        Set<Long> requestedIds = params.getItems().stream()
+                .map(item -> item.get("id"))
+                .filter(Objects::nonNull)
+                .map(id -> Long.valueOf(id.toString()))
+                .collect(Collectors.toSet());
+        // 宸茬敓鎴愬伐浣滄。鐨勬槑缁嗕笉鍏佽鍒犻櫎
+        for (Long existingId : existingIds) {
+            if (!requestedIds.contains(existingId) && hasGeneratedTask(orders.getId(), existingId)) {
+                throw new CoolException("璇ユ槑缁嗗凡鐢熸垚宸ヤ綔妗o紝涓嶈兘鍒犻櫎");
+            }
+        }
+        // 宸茬敓鎴愬伐浣滄。鐨勬槑缁嗕笉鍏佽淇敼
+        for (Map<String, Object> item : params.getItems()) {
+            Object idObj = item.get("id");
+            if (idObj != null && hasGeneratedTask(orders.getId(), Long.valueOf(idObj.toString()))) {
+                throw new CoolException("璇ユ槑缁嗗凡鐢熸垚宸ヤ綔妗o紝涓嶈兘淇敼");
+            }
+        }
         try {
             svaeOrUpdateOrderItem(params, loginUserId);
         } catch (Exception e) {
             throw new CoolException(e.getMessage());
         }
+        // 瀵规湰娆¤鍒犻櫎鐨勬槑缁嗭紙浠呭垵濮嬪寲鐘舵�侊級锛氬厛鍚屾搴撲綅鐘舵�侊紝鍐嶅垹闄ゆ槑缁嗚褰�
+        for (Long existingId : existingIds) {
+            if (!requestedIds.contains(existingId)) {
+                syncLocStatusOnOrderItemRemoved(orders.getId(), existingId, loginUserId);
+                outStockItemService.removeById(existingId);
+            }
+        }
+        // 閲嶆柊姹囨�讳富鍗曟暟閲忥紙鍒犻櫎鏄庣粏鍚庯級
+        List<WkOrderItem> afterItems = asnOrderItemService.list(new LambdaQueryWrapper<WkOrderItem>()
+                .eq(WkOrderItem::getOrderId, orders.getId()));
+        Double sum = afterItems.stream().mapToDouble(WkOrderItem::getAnfme).sum();
+        orders.setAnfme(sum);
+        this.updateById(orders);
         return R.ok();
+    }
+
+    /**
+     * 鍒ゆ柇鍑哄簱鍗曟槑缁嗘槸鍚﹀凡鐢熸垚宸ヤ綔妗o紙瀛樺湪鍏宠仈鐨勪换鍔℃槑缁嗭級
+     */
+    private boolean hasGeneratedTask(Long orderId, Long orderItemId) {
+        return taskItemService.count(new LambdaQueryWrapper<TaskItem>()
+                .eq(TaskItem::getSourceId, orderId)
+                .eq(TaskItem::getOrderItemId, orderItemId)) > 0;
+    }
+
+    /**
+     * 鍑哄簱鍗曟槑缁嗚鍒犻櫎鏃跺悓姝ュ簱浣嶇姸鎬侊細閲婃斁璇ユ槑缁嗗叧鑱旂殑搴撲綅棰勭害銆佸洖婊� LocItem.workQty銆佹仮澶嶅簱浣嶄负鍦ㄥ簱(F)
+     */
+    private void syncLocStatusOnOrderItemRemoved(Long orderId, Long orderItemId, Long loginUserId) {
+        List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>()
+                .eq(TaskItem::getSourceId, orderId)
+                .eq(TaskItem::getOrderItemId, orderItemId));
+        if (taskItems.isEmpty()) {
+            return;
+        }
+        Set<Long> affectedLocIds = new HashSet<>();
+        Date now = new Date();
+        for (TaskItem taskItem : taskItems) {
+            if (taskItem.getSource() == null) {
+                continue;
+            }
+            LocItem locItem = locItemService.getById(taskItem.getSource());
+            if (locItem == null) {
+                continue;
+            }
+            Double anfme = taskItem.getAnfme() != null ? taskItem.getAnfme() : 0.0;
+            Double newWorkQty = Math.round((locItem.getWorkQty() - anfme) * 1000000) / 1000000.0;
+            locItem.setWorkQty(newWorkQty >= 0 ? newWorkQty : 0)
+                    .setOrderId(null)
+                    .setOrderItemId(null)
+                    .setUpdateBy(loginUserId)
+                    .setUpdateTime(now);
+            locItemService.updateById(locItem);
+            affectedLocIds.add(locItem.getLocId());
+        }
+        for (Long locId : affectedLocIds) {
+            long stillReserved = locItemService.count(new LambdaQueryWrapper<LocItem>()
+                    .eq(LocItem::getLocId, locId)
+                    .isNotNull(LocItem::getOrderId));
+            if (stillReserved == 0) {
+                Loc loc = locService.getById(locId);
+                if (loc != null && LocStsType.LOC_STS_TYPE_R.type.equals(loc.getUseStatus())) {
+                    loc.setUseStatus(LocStsType.LOC_STS_TYPE_F.type)
+                            .setUpdateBy(loginUserId)
+                            .setUpdateTime(now);
+                    locService.updateById(loc);
+                }
+            }
+        }
     }
 
     @Override
@@ -478,23 +644,104 @@
             if (Objects.isNull(param) || StringUtils.isBlank(param.getLocCode())) {
                 continue;
             }
-            Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, param.getLocCode()).eq(Loc::getBarcode, param.getBarcode()));
+            // 淇锛氭瀯寤哄簱浣嶆煡璇㈡潯浠讹紝濡傛灉barcode涓虹┖锛屽彧鎸塴ocCode鏌ヨ
+            LambdaQueryWrapper<Loc> locQueryWrapper = new LambdaQueryWrapper<Loc>()
+                    .eq(Loc::getCode, param.getLocCode());
+            if (StringUtils.isNotBlank(param.getBarcode())) {
+                locQueryWrapper.eq(Loc::getBarcode, param.getBarcode());
+            }
+            Loc loc = locService.getOne(locQueryWrapper);
             if (!Objects.isNull(loc)) {
                 List<LocItem> locItems = new ArrayList<>();
                 LocItem locItem = locItemService.getById(param.getId());
+                
+                if (Objects.isNull(locItem)) {
+                    throw new CoolException("搴撲綅鏄庣粏涓嶅瓨鍦紝ID锛�" + param.getId());
+                }
 
-                WkOrderItem orderItem = outStockItemService.getOne(new LambdaQueryWrapper<WkOrderItem>()
+                // 淇锛氭瀯寤烘煡璇㈡潯浠讹紝鍏堟瀯寤哄熀纭�鏉′欢锛屽啀鏍规嵁鍊兼槸鍚︿负绌哄姩鎬佹坊鍔�
+                // 浼樺厛浣跨敤渚涘簲鍟嗘壒娆″尮閰嶏紝濡傛灉娌℃湁鍒欎娇鐢ㄥ簱瀛樻壒娆″尮閰�
+                LambdaQueryWrapper<WkOrderItem> orderItemWrapper = new LambdaQueryWrapper<WkOrderItem>()
                         .eq(WkOrderItem::getOrderId, outId)
-                        .eq(StringUtils.isNotBlank(locItem.getBatch()), WkOrderItem::getSplrBatch, locItem.getBatch())
-                        .eq(StringUtils.isNotBlank(locItem.getFieldsIndex()), WkOrderItem::getFieldsIndex, locItem.getFieldsIndex())
-                        .eq(WkOrderItem::getMatnrId, locItem.getMatnrId()));
+                        .eq(WkOrderItem::getMatnrId, locItem.getMatnrId());
+                
+                // 浼樺厛浣跨敤渚涘簲鍟嗘壒娆″尮閰�
+                if (StringUtils.isNotBlank(locItem.getSplrBatch())) {
+                    orderItemWrapper.eq(WkOrderItem::getSplrBatch, locItem.getSplrBatch());
+                } else if (StringUtils.isNotBlank(locItem.getBatch())) {
+                    // 濡傛灉LocItem鍙湁batch瀛楁锛屽皾璇曞悓鏃跺尮閰峎kOrderItem鐨刡atch鍜宻plrBatch瀛楁
+                    // 鍥犱负鏌愪簺鎯呭喌涓婰ocItem鐨刡atch鍙兘瀵瑰簲WkOrderItem鐨剆plrBatch
+                    orderItemWrapper.and(wrapper -> wrapper
+                            .eq(WkOrderItem::getBatch, locItem.getBatch())
+                            .or()
+                            .eq(WkOrderItem::getSplrBatch, locItem.getBatch())
+                    );
+                }
+                
+                if (StringUtils.isNotBlank(locItem.getFieldsIndex())) {
+                    orderItemWrapper.eq(WkOrderItem::getFieldsIndex, locItem.getFieldsIndex());
+                }
+                // 鍚屼竴鍑哄簱鍗曚笅鍚屼竴鐗╂枡鍙兘鏈夊鏉℃槑缁嗭紙濡傚琛屽悎骞讹級锛岀敤 list 鍙栦粛鏈夊墿浣欐暟閲忕殑绗竴鏉★紝閬垮厤 getOne 杩斿洖澶氭潯鎶� TooManyResultsException
+                List<WkOrderItem> orderItemCandidates = outStockItemService.list(orderItemWrapper);
+                WkOrderItem orderItem = orderItemCandidates.stream()
+                        .filter(o -> o.getAnfme() != null && o.getWorkQty() != null && o.getAnfme().compareTo(o.getWorkQty()) > 0)
+                        .findFirst()
+                        .orElse(null);
 
+                // 濡傛灉鎵句笉鍒板崟鎹槑缁嗭紝涓擫ocItem鏉ヨ嚜搴撳瓨璋冩暣锛屽垯鑷姩鍒涘缓WkOrderItem
                 if (Objects.isNull(orderItem)) {
-                    throw new CoolException("鍗曟嵁鏄庣粏涓嶅瓨鍦紒锛�");
+                    // 妫�鏌ユ槸鍚︽槸搴撳瓨璋冩暣浜х敓鐨勫簱瀛�
+                    if (locItem.getWkType() != null && 
+                        locItem.getWkType().equals(Short.parseShort(OrderWorkType.ORDER_WORK_TYPE_STOCK_REVISE.type))) {
+                        // 鑾峰彇鍑哄簱鍗曚俊鎭�
+                        WkOrder outOrder = outStockService.getById(outId);
+                        if (Objects.isNull(outOrder)) {
+                            throw new CoolException("鍑哄簱鍗曟嵁涓嶅瓨鍦紒锛�");
+                        }
+                        
+                        log.info("搴撳瓨璋冩暣浜х敓鐨勫簱瀛橈紝鑷姩鍒涘缓WkOrderItem - 鍑哄簱鍗旾D锛歿}锛岀墿鏂橧D锛歿}锛屾壒娆★細{}", 
+                                outId, locItem.getMatnrId(), locItem.getBatch());
+                        
+                        // 鍒涘缓WkOrderItem
+                        orderItem = new WkOrderItem();
+                        orderItem.setOrderId(outId)
+                                .setOrderCode(outOrder.getCode())
+                                .setMatnrId(locItem.getMatnrId())
+                                .setMatnrCode(locItem.getMatnrCode())
+                                .setMaktx(locItem.getMaktx())
+                                .setBatch(StringUtils.isNotBlank(param.getBatch()) ? param.getBatch() : locItem.getBatch())
+                                .setSplrBatch(StringUtils.isNotBlank(locItem.getSplrBatch()) ? locItem.getSplrBatch() : 
+                                             (StringUtils.isNotBlank(locItem.getBatch()) ? locItem.getBatch() : null))
+                                .setFieldsIndex(locItem.getFieldsIndex())
+                                .setAnfme(param.getOutQty())
+                                .setWorkQty(0.0)
+                                .setStockUnit(locItem.getUnit())
+                                .setPurUnit(locItem.getUnit())
+                                .setSpec(locItem.getSpec())
+                                .setModel(locItem.getModel())
+                                .setCreateBy(loginUserId)
+                                .setUpdateBy(loginUserId)
+                                .setCreateTime(new Date())
+                                .setUpdateTime(new Date());
+                        
+                        if (!outStockItemService.save(orderItem)) {
+                            throw new CoolException("搴撳瓨璋冩暣鍗曟嵁鏄庣粏鍒涘缓澶辫触锛侊紒");
+                        }
+                        
+                        log.info("WkOrderItem鍒涘缓鎴愬姛 - ID锛歿}锛屽嚭搴撳崟ID锛歿}锛岀墿鏂橧D锛歿}", 
+                                orderItem.getId(), outId, locItem.getMatnrId());
+                    } else {
+                        throw new CoolException("鍗曟嵁鏄庣粏涓嶅瓨鍦紒锛佸嚭搴撳崟ID锛�" + outId + "锛岀墿鏂橧D锛�" + locItem.getMatnrId() + 
+                                (StringUtils.isNotBlank(locItem.getSplrBatch()) ? "锛屼緵搴斿晢鎵规锛�" + locItem.getSplrBatch() : 
+                                 StringUtils.isNotBlank(locItem.getBatch()) ? "锛屽簱瀛樻壒娆★細" + locItem.getBatch() : "") +
+                                (StringUtils.isNotBlank(locItem.getFieldsIndex()) ? "锛屽瓧娈电储寮曪細" + locItem.getFieldsIndex() : ""));
+                    }
                 }
 
                 locItem.setOutQty(param.getOutQty())
                         .setBatch(param.getBatch())
+                        .setOrderId(outId)
+                        .setOrderItemId(orderItem.getId())
                         .setSourceId(outId)
                         .setSourceCode(orderItem.getOrderCode())
                         .setSource(orderItem.getId());
@@ -552,7 +799,12 @@
                 TaskType.TASK_TYPE_OUT.type,
                 TaskType.TASK_TYPE_MERGE_OUT.type,
                 TaskType.TASK_TYPE_PICK_AGAIN_OUT.type);
-        List<DeviceSite> sites = deviceSiteService.list(new LambdaQueryWrapper<DeviceSite>().in(DeviceSite::getType, list).groupBy(DeviceSite::getSite));
+        // 鍏堟煡鍏ㄩ儴鍐嶆寜 site 鍘婚噸锛岄伩鍏� GROUP BY 涓� only_full_group_by 鍐茬獊
+        List<DeviceSite> all = deviceSiteService.list(new LambdaQueryWrapper<DeviceSite>().in(DeviceSite::getType, list));
+        List<DeviceSite> sites = all.stream()
+                .collect(Collectors.toMap(DeviceSite::getSite, d -> d, (a, b) -> a))
+                .values().stream()
+                .collect(Collectors.toList());
         return R.ok(sites);
     }
 
@@ -605,9 +857,8 @@
         Set<ExistDto> existDtos = new HashSet<>();
         for (WkOrderItem wkOrderItem : wkOrderItems) {
             BigDecimal issued = new BigDecimal(wkOrderItem.getAnfme().toString())
-                    .subtract(new BigDecimal(wkOrderItem.getWorkQty().toString())
-                    );
-            if (issued.doubleValue() <= 0) {
+                    .subtract(new BigDecimal(wkOrderItem.getWorkQty().toString()));
+            if (issued.compareTo(ISSUED_TOLERANCE) <= 0) {
                 continue;
             }
             List<LocItem> locItems = new ArrayList<>();
@@ -621,47 +872,57 @@
             for (LocItem locItem : locItems) {
                 Loc loc = locService.getById(locItem.getLocId());
                 List<LocItem> itemList = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocCode, locItem.getLocCode()));
-                if (issued.doubleValue() > 0) {
-                    ExistDto existDto = new ExistDto().setBatch(locItem.getBatch()).setMatnr(locItem.getMatnrCode()).setLocNo(locItem.getLocCode());
-                    if (existDtos.add(existDto)) {
-                        locItem.setOutQty(issued.doubleValue() >= locItem.getAnfme() ? locItem.getAnfme() : issued.doubleValue());
-                        locItem.setBarcode(loc.getBarcode());
-                        OrderOutItemDto orderOutItemDto = new OrderOutItemDto();
-                        orderOutItemDto.setLocItem(locItem);
+                if (issued.compareTo(ISSUED_TOLERANCE) <= 0) {
+                    break;
+                }
+                // 璇ュ簱浣嶅彲鍒嗛厤鏁伴噺锛氬彇鏈寰呭垎閰嶄笌搴撲綅搴撳瓨鐨勮緝灏忓��
+                double allocatable = Math.min(issued.doubleValue(), locItem.getAnfme() != null ? locItem.getAnfme() : 0);
+                // 褰撳垎閰嶉噺绛変簬搴撲綅搴撳瓨鏃讹紝浣跨敤搴撲綅搴撳瓨绮惧害浣滀负鍑哄簱鏁伴噺锛岄伩鍏嶆埅鏂鑷寸晫闈㈡樉绀�/搴撳瓨鏍¢獙涓嶄竴鑷达紙濡傚簱瀛�15.123457琚埅鎴�15.123锛�
+                double outQtyToSet = (locItem.getAnfme() != null && Math.abs(allocatable - locItem.getAnfme()) < 1e-6)
+                        ? locItem.getAnfme() : allocatable;
+                ExistDto existDto = new ExistDto().setBatch(locItem.getBatch()).setMatnr(locItem.getMatnrCode()).setLocNo(locItem.getLocCode());
+                if (existDtos.add(existDto)) {
+                    // 棣栨浣跨敤璇ュ簱浣嶏細鍔犲叆鍒楄〃骞舵墸鍑� issued
+                    locItem.setOutQty(outQtyToSet);
+                    locItem.setBarcode(loc.getBarcode());
+                    OrderOutItemDto orderOutItemDto = new OrderOutItemDto();
+                    orderOutItemDto.setLocItem(locItem);
 
-                        List<DeviceSite> deviceSites = deviceSiteService.list(new LambdaQueryWrapper<DeviceSite>()
-                                .eq(DeviceSite::getChannel, loc.getChannel())
-                                .eq(DeviceSite::getType, issued.doubleValue() >= locItem.getAnfme() && itemList.size() == 1 ? TaskType.TASK_TYPE_OUT.type : TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)
-                        );
+                    List<DeviceSite> deviceSites = deviceSiteService.list(new LambdaQueryWrapper<DeviceSite>()
+                            .eq(DeviceSite::getChannel, loc.getChannel())
+                            .eq(DeviceSite::getType, issued.doubleValue() >= locItem.getAnfme() && itemList.size() == 1 ? TaskType.TASK_TYPE_OUT.type : TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)
+                    );
 
-                        if (!deviceSites.isEmpty()) {
-                            List<OrderOutItemDto.staListDto> maps = new ArrayList<>();
-                            for (DeviceSite sta : deviceSites) {
-                                OrderOutItemDto.staListDto staListDto = new OrderOutItemDto.staListDto();
-                                staListDto.setStaNo(sta.getSite());
-                                staListDto.setStaName(sta.getSite());
-                                maps.add(staListDto);
-                            }
-                            orderOutItemDto.setStaNos(maps);
-                            //榛樿鑾峰彇绗竴绔欑偣
-                            DeviceSite deviceSite = deviceSites.stream().findFirst().get();
-                            orderOutItemDto.setSiteNo(deviceSite.getSite());
+                    if (!deviceSites.isEmpty()) {
+                        List<OrderOutItemDto.staListDto> maps = new ArrayList<>();
+                        for (DeviceSite sta : deviceSites) {
+                            OrderOutItemDto.staListDto staListDto = new OrderOutItemDto.staListDto();
+                            staListDto.setStaNo(sta.getSite());
+                            staListDto.setStaName(sta.getSite());
+                            maps.add(staListDto);
                         }
-
-                        list.add(orderOutItemDto);
-
-                        issued = issued.subtract(new BigDecimal(locItem.getAnfme().toString()));
+                        orderOutItemDto.setStaNos(maps);
+                        //榛樿鑾峰彇绗竴绔欑偣
+                        DeviceSite deviceSite = deviceSites.stream().findFirst().get();
+                        orderOutItemDto.setSiteNo(deviceSite.getSite());
                     }
+
+                    list.add(orderOutItemDto);
+                    issued = issued.subtract(new BigDecimal(locItem.getAnfme().toString()));
+                } else {
+                    // 璇ュ簱浣嶅凡琚墠搴忚鍗曡鍗犵敤锛氬彧鎵e噺 issued锛屼笉閲嶅鍔犲叆鍒楄〃锛岄伩鍏嶄骇鐢熲�滃簱瀛樹笉瓒斥�濊剰鏁版嵁
+                    issued = issued.subtract(new BigDecimal(String.valueOf(allocatable)));
                 }
             }
-            if (issued.doubleValue() > 0) {
+            if (issued.compareTo(ISSUED_TOLERANCE) > 0) {
+                double remaining = issued.setScale(6, RoundingMode.HALF_UP).doubleValue();
                 LocItem locItem = new LocItem()
                         .setId(new Random().nextLong())
                         .setMatnrCode(wkOrderItem.getMatnrCode())
                         .setMaktx(wkOrderItem.getMaktx())
                         .setAnfme(0.00)
-                        .setWorkQty(issued.doubleValue())
-                        .setOutQty(issued.doubleValue())
+                        .setWorkQty(remaining)
+                        .setOutQty(remaining)
                         .setUnit(wkOrderItem.getStockUnit())
                         .setBatch(wkOrderItem.getSplrBatch());
                 OrderOutItemDto orderOutItemDto = new OrderOutItemDto();
@@ -711,7 +972,7 @@
                         p1.getUnit(),
                         p1.getTrackCode(),
                         p1.getFieldsIndex(),
-                        Math.round((p1.getAnfme() + p2.getAnfme()) * 100) / 100.0,
+                        Math.round((p1.getAnfme() + p2.getAnfme())* 1000000) / 1000000.0,
                         p1.getWorkQty(),
                         p1.getTenantId(),
                         p1.getStatus(),
@@ -727,4 +988,25 @@
 
         return waveItems;
     }
+
+
+    /**
+     * @param id
+     * @return
+     * @author Ryan
+     * @description 瀹屾垚鍑哄簱鍗�
+     * @time 2025/4/25 10:07
+     */
+    @Override
+    public R completeOutOrderById(Long id) {
+        WkOrder order = this.getById(id);
+        if (Objects.isNull(order)) {
+            return R.error("鍑哄簱鍗曚笉瀛樺湪锛侊紒");
+        }
+        order.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_DONE.val);
+        if (!this.updateById(order)) {
+            throw new CoolException("瀹屾垚鍑哄簱鍗曞け璐ワ紒锛�");
+        }
+         return R.ok("瀹屾垚鍑哄簱鍗曟垚鍔燂紒锛�");
+    }
 }

--
Gitblit v1.9.1