Quellcode durchsuchen

订单余量修改

chenxiaofei vor 1 Monat
Ursprung
Commit
02fd4f6046

+ 131 - 31
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/KwtLogisticsConsignmentService.java

@@ -2452,13 +2452,14 @@ public class KwtLogisticsConsignmentService {
         Map<String, KwtLogisticsOrderAddress> addressMap = addressMapFuture.join();
         Map<Long, KwtLogisticsOrderContract> contractMap = contractMapFuture.join();
         Map<Long, List<KwtWaybillOrderSubtask>> subtaskMap = processSubtaskData(subtaskListFuture.join());
+        Map<Long, List<KwtWaybillOrderTicket>> ticketMap = processTicketData(subtaskListFuture.join());
         Map<Long, OrderDetailVo> tradeMap = tradeMapFuture.join();
         Map<Long, List<KwtLogisticsOrder>> tradeLogOrderMap = groupByTradeOrder(records);
         log.debug("查询结果处理完成");
 
         log.debug("相关订单数据获取完成");
         return new RelatedOrderData(unitMap, goodsData, addressMap, contractMap,
-                subtaskMap, tradeMap, tradeLogOrderMap);
+                subtaskMap, ticketMap, tradeMap, tradeLogOrderMap);
     }
 
     /**
@@ -2528,6 +2529,31 @@ public class KwtLogisticsConsignmentService {
                 .collect(Collectors.groupingBy(KwtWaybillOrderSubtask::getLOrderId));
     }
 
+    /**
+     * 处理磅单数据,构建运单ID与磅单列表映射
+     */
+    private Map<Long, List<KwtWaybillOrderTicket>> processTicketData(List<KwtWaybillOrderSubtask> subtaskList) {
+        if (CollectionUtils.isEmpty(subtaskList)) {
+            return Maps.newHashMap();
+        }
+        List<Long> wOrderIds = subtaskList.stream()
+                .filter(Objects::nonNull)
+                .map(KwtWaybillOrderSubtask::getWOrderId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(wOrderIds)) {
+            return Maps.newHashMap();
+        }
+        List<KwtWaybillOrderTicket> tickets = waybillOrderTicketRepository.queryByWOrderIds(wOrderIds);
+        if (CollectionUtils.isEmpty(tickets)) {
+            return Maps.newHashMap();
+        }
+        return tickets.stream()
+                .filter(Objects::nonNull)
+                .collect(Collectors.groupingBy(KwtWaybillOrderTicket::getWOrderId));
+    }
+
     /**
      * 按贸易订单分组
      */
@@ -2584,7 +2610,8 @@ public class KwtLogisticsConsignmentService {
                         dictMap,
                         relatedData.getTradeMap(),
                         relatedData.getTradeLogOrderMap(),
-                        relatedData.getSubtaskMap()))
+                        relatedData.getSubtaskMap(),
+                        relatedData.getTicketMap()))
                 .collect(Collectors.toList());
     }
 
@@ -2664,6 +2691,7 @@ public class KwtLogisticsConsignmentService {
         private final Map<String, KwtLogisticsOrderAddress> addressMap;
         private final Map<Long, KwtLogisticsOrderContract> contractMap;
         private final Map<Long, List<KwtWaybillOrderSubtask>> subtaskMap;
+        private final Map<Long, List<KwtWaybillOrderTicket>> ticketMap;
         private final Map<Long, OrderDetailVo> tradeMap;
         private final Map<Long, List<KwtLogisticsOrder>> tradeLogOrderMap;
 
@@ -2672,6 +2700,7 @@ public class KwtLogisticsConsignmentService {
                                 Map<String, KwtLogisticsOrderAddress> addressMap,
                                 Map<Long, KwtLogisticsOrderContract> contractMap,
                                 Map<Long, List<KwtWaybillOrderSubtask>> subtaskMap,
+                                Map<Long, List<KwtWaybillOrderTicket>> ticketMap,
                                 Map<Long, OrderDetailVo> tradeMap,
                                 Map<Long, List<KwtLogisticsOrder>> tradeLogOrderMap) {
             this.unitMap = unitMap;
@@ -2679,6 +2708,7 @@ public class KwtLogisticsConsignmentService {
             this.addressMap = addressMap;
             this.contractMap = contractMap;
             this.subtaskMap = subtaskMap;
+            this.ticketMap = ticketMap;
             this.tradeMap = tradeMap;
             this.tradeLogOrderMap = tradeLogOrderMap;
         }
@@ -2703,6 +2733,10 @@ public class KwtLogisticsConsignmentService {
             return subtaskMap;
         }
 
+        public Map<Long, List<KwtWaybillOrderTicket>> getTicketMap() {
+            return ticketMap;
+        }
+
         public Map<Long, OrderDetailVo> getTradeMap() {
             return tradeMap;
         }
@@ -3033,7 +3067,8 @@ public class KwtLogisticsConsignmentService {
                                                             Map<String, Map<String, String>> dictValueAndDictResDtoMap,
                                                             Map<Long, OrderDetailVo> tradeIdAndOrderDetailVoMap,
                                                             Map<Long, List<KwtLogisticsOrder>> tradeIdAndLogOrderList,
-                                                            Map<Long, List<KwtWaybillOrderSubtask>> logisticsOrderIdAndSubtaskList) {
+                                                            Map<Long, List<KwtWaybillOrderSubtask>> logisticsOrderIdAndSubtaskList,
+                                                            Map<Long, List<KwtWaybillOrderTicket>> waybillOrderIdAndTicketList) {
         LogisticsOrderResp logisticsOrderResp = new LogisticsOrderResp();
         logisticsOrderResp.setLogisticsOrderId(String.valueOf(kwtLogisticsOrder.getId()));
         logisticsOrderResp.setLogisticsOrderNo(kwtLogisticsOrder.getLOrderNo());
@@ -3132,53 +3167,118 @@ public class KwtLogisticsConsignmentService {
         logisticsOrderResp.setStatus(String.valueOf(kwtLogisticsOrder.getStatus()));
         logisticsOrderResp.setStatusDesc(LogisticsOrderV1Enum.getDesc(kwtLogisticsOrder.getStatus()));
         //设置余量
-        BigDecimal orderSurplus = getSupAmount(kwtLogisticsOrder.getTOrderId(), tradeIdAndOrderDetailVoMap, tradeIdAndLogOrderList, logisticsOrderIdAndSubtaskList);
+        BigDecimal orderSurplus = getSupAmount(kwtLogisticsOrder.getTOrderId(), tradeIdAndOrderDetailVoMap, tradeIdAndLogOrderList,
+                logisticsOrderIdAndSubtaskList, waybillOrderIdAndTicketList);
         logisticsOrderResp.setOrderSurplus(orderSurplus.toPlainString() + kwtLogisticsOrder.getUnit());
         logisticsOrderResp.setRemainingAmount(orderSurplus);
         return logisticsOrderResp;
     }
 
+    /**
+     * 计算贸易订单的剩余可分配量(余量)
+     * <p>
+     * 计算逻辑:订单余量 = 贸易订单总货物量 - 已使用的量
+     * 其中“已使用的量”包括:
+     * 1. 子运单的委托量(EntrustAmount)
+     * 2. 磅单的实际装/卸货量(根据计费模式决定取装货还是卸货)
+     * </p>
+     *
+     * @param tradeOrderId                贸易订单ID
+     * @param tradeIdAndOrderDetailVoMap  贸易订单ID与详情对象的映射
+     * @param tradeIdAndLogOrderList      贸易订单ID与关联物流订单列表的映射
+     * @param logisticsOrderIdAndSubtaskList 物流订单ID与子运单列表的映射
+     * @param waybillOrderIdAndTicketList    主运单ID与磅单列表的映射
+     * @return 剩余可分配量,保留两位小数,最小为0
+     */
     private static BigDecimal getSupAmount(Long tradeOrderId,
                                            Map<Long, OrderDetailVo> tradeIdAndOrderDetailVoMap,
                                            Map<Long, List<KwtLogisticsOrder>> tradeIdAndLogOrderList,
-                                           Map<Long, List<KwtWaybillOrderSubtask>> logisticsOrderIdAndSubtaskList) {
-        // KwtLogisticsOrder order = logOrderMap.getOrDefault(wbOrder.getLOrderId(), new KwtLogisticsOrder());
+                                           Map<Long, List<KwtWaybillOrderSubtask>> logisticsOrderIdAndSubtaskList,
+                                           Map<Long, List<KwtWaybillOrderTicket>> waybillOrderIdAndTicketList) {
+        log.debug("开始计算贸易订单余量,tradeOrderId: {}", tradeOrderId);
+
+        // 1. 获取贸易订单基础信息及总货物量
         OrderDetailVo detailVo = tradeIdAndOrderDetailVoMap.getOrDefault(tradeOrderId, new OrderDetailVo());
         BigDecimal tradeAmount = Optional.ofNullable(detailVo).map(OrderDetailVo::getAmount).orElse(BigDecimal.ZERO);
+        log.debug("贸易订单总货物量: {}", tradeAmount);
+
+        // 2. 获取该贸易订单关联的所有物流订单
         List<KwtLogisticsOrder> kwtLogisticsOrders = tradeIdAndLogOrderList.get(tradeOrderId);
-        BigDecimal logTotatalAmount = BigDecimal.ZERO;
-        if (CollectionUtils.isNotEmpty(kwtLogisticsOrders)) {
-            String billingMode = kwtLogisticsOrders.get(0).getBillingMode();
+        BigDecimal usedAmount = BigDecimal.ZERO;
 
+        if (CollectionUtils.isNotEmpty(kwtLogisticsOrders)) {
+            log.debug("关联物流订单数量: {}", kwtLogisticsOrders.size());
             for (KwtLogisticsOrder kwtLogisticsOrder : kwtLogisticsOrders) {
-                List<KwtWaybillOrderSubtask> waybillOrderSubtasks = logisticsOrderIdAndSubtaskList.getOrDefault(kwtLogisticsOrder.getId(), new ArrayList<>());
-                BigDecimal loadAmountSum = waybillOrderSubtasks.stream()
-                        .filter(x -> !Arrays.asList(CarWaybillV1Enum.COMPLETED.getCode(), CarWaybillV1Enum.CANCELLED.getCode()).contains(x.getStatus()))
-                        .map(KwtWaybillOrderSubtask::getEntrustAmount)
-                        .filter(Objects::nonNull)
-                        .reduce(BigDecimal.ZERO, BigDecimal::add);
-                //logTotatalAmount = logTotatalAmount.add(loadAmountSum);
+                Long logOrderId = kwtLogisticsOrder.getId();
+                // 获取当前物流订单下的所有子运单
+                List<KwtWaybillOrderSubtask> waybillOrderSubtasks = logisticsOrderIdAndSubtaskList.getOrDefault(logOrderId, Collections.emptyList());
+                
+                if (CollectionUtils.isEmpty(waybillOrderSubtasks)) {
+                    log.debug("物流订单 {} 下无子运单,跳过", logOrderId);
+                    continue;
+                }
+
+                // 3. 根据计费模式确定磅单类型(装货或卸货)
+                // CHARGING_TYPE_1: 按装货量计费 -> 对应装货磅单 (SHIPMENT)
+                // CHARGING_TYPE_2: 按卸货量计费 -> 对应卸货磅单 (TAKE)
+                Integer ticketType;
+                String billingMode = kwtLogisticsOrder.getBillingMode();
                 if (org.apache.commons.lang3.StringUtils.equals(billingMode, DictEnum.CHARGING_TYPE_1.getValue())) {
-                    BigDecimal unloadAmountSum = waybillOrderSubtasks.stream()
-                            .filter(x -> !Objects.equals(x.getStatus(), CarWaybillV1Enum.CANCELLED.getCode()))
-                            .map(KwtWaybillOrderSubtask::getLoadAmount)
-                            .filter(Objects::nonNull)
-                            .reduce(BigDecimal.ZERO, BigDecimal::add);
-                    logTotatalAmount = logTotatalAmount.add(loadAmountSum).add(unloadAmountSum);
+                    ticketType = AddressTypeEnum.SHIPMENT.getCode();
                 } else if (org.apache.commons.lang3.StringUtils.equals(billingMode, DictEnum.CHARGING_TYPE_2.getValue())) {
-                    BigDecimal unloadAmountSum = waybillOrderSubtasks.stream()
-                            .filter(x -> !Objects.equals(x.getStatus(), CarWaybillV1Enum.CANCELLED.getCode()))
-                            .map(KwtWaybillOrderSubtask::getUnloadAmount)
-                            .filter(Objects::nonNull)
-                            .reduce(BigDecimal.ZERO, BigDecimal::add);
-                    logTotatalAmount = logTotatalAmount.add(loadAmountSum).add(unloadAmountSum);
+                    ticketType = AddressTypeEnum.TAKE.getCode();
+                } else {
+                    // 未知计费模式,记录警告并跳过该物流订单的计算,避免数据错误
+                    log.warn("余量计算跳过未知计费模式,tradeOrderId:{}, logOrderId:{}, billingMode:{}",
+                            tradeOrderId, logOrderId, billingMode);
+                    continue;
                 }
 
-                //logTotatalAmount = logTotatalAmount.add(unloadAmountSum);
+                // 4. 计算子运单委托量总和
+                // 过滤条件:对象非空、状态非取消、委托量非空
+                List<Integer> statusList = Arrays.asList(CarWaybillV1Enum.COMPLETED.getCode(), CarWaybillV1Enum.CANCELLED.getCode());
+                BigDecimal entrustAmount = waybillOrderSubtasks.stream()
+                        .filter(Objects::nonNull)
+                        .filter(subtask -> !statusList.contains(subtask.getStatus()))
+                        .map(KwtWaybillOrderSubtask::getEntrustAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+                // 5. 计算磅单实际量总和
+                // 逻辑:子运单 -> 主运单ID -> 磅单列表 -> 过滤特定类型 -> 累加金额/数量
+                BigDecimal ticketAmount = waybillOrderSubtasks.stream()
+                        .filter(Objects::nonNull)
+                        .filter(subtask -> !Objects.equals(subtask.getStatus(), CarWaybillV1Enum.CANCELLED.getCode()))
+                        .map(KwtWaybillOrderSubtask::getWOrderId)
+                        .filter(Objects::nonNull)
+                        .flatMap(wOrderId -> waybillOrderIdAndTicketList.getOrDefault(wOrderId, Collections.emptyList()).stream())
+                        .filter(Objects::nonNull)
+                        // 只统计与计费模式匹配的磅单类型(装或卸)
+                        .filter(ticket -> Objects.equals(ticket.getType(), ticketType))
+                        .map(KwtWaybillOrderTicket::getAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+                // 累加当前物流订单的已使用量
+                BigDecimal currentUsed = entrustAmount.add(ticketAmount);
+                usedAmount = usedAmount.add(currentUsed);
+                
+                log.debug("物流订单 {} 计算详情: 委托量={}, 磅单量={}, 计费类型={}", 
+                        logOrderId, entrustAmount, ticketAmount, ticketType);
             }
         }
-        BigDecimal subSurplus = tradeAmount.subtract(logTotatalAmount).compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : tradeAmount.subtract(logTotatalAmount);
-        return subSurplus.setScale(2, RoundingMode.HALF_UP);
+
+        // 6. 计算最终余量:总量 - 已用量,若结果小于0则置为0
+        BigDecimal surplus = tradeAmount.subtract(usedAmount);
+        if (surplus.compareTo(BigDecimal.ZERO) <= 0) {
+            log.info("贸易订单 {} 余量计算结果为负或零,重置为0。总量: {}, 已用: {}", tradeOrderId, tradeAmount, usedAmount);
+            surplus = BigDecimal.ZERO;
+        } else {
+            log.debug("贸易订单 {} 余量计算正常。总量: {}, 已用: {}, 余量: {}", tradeOrderId, tradeAmount, usedAmount, surplus);
+        }
+
+        // 保留两位小数,四舍五入
+        return surplus.setScale(2, RoundingMode.HALF_UP);
     }
 
     public LogisticsOrderDetailResp getLogisticsOrderDetail(@Valid LogisticsOrderReq req) {

+ 132 - 33
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/app/WaybillOrderService.java

@@ -273,6 +273,8 @@ public class WaybillOrderService {
         }
         Map<Long, List<KwtWaybillOrderSubtask>> logOrderIdAndSubtaskMap = orderSubtaskList.stream()
                 .collect(Collectors.groupingBy(KwtWaybillOrderSubtask::getLOrderId));
+        // 预加载运单磅单信息,避免在余量计算中出现 N+1 查询
+        Map<Long, List<KwtWaybillOrderTicket>> waybillOrderIdAndTicketList = getWaybillOrderIdAndTicketList(orderSubtaskList);
 
         //获取贸易订单
         List<OrderDetailVo> orderDetailVos = tradeOrderInfoService.queryByTradeOrderIds(tradeOrderIds);
@@ -292,7 +294,7 @@ public class WaybillOrderService {
                 .map(order -> {
                     return getLogisticsOrderResp(order, logOrderIdAndGoodsMap, goodsIdAndGoodsMap, logOrderIdAndUnitMap,
                             tOrderIdAndUnitMap, logOrderIdAndAddressMap, logOrderIdAndCirculateMap, tradeIdAndOrderDetailVoMap,
-                            tradeIdAndLogOrderList, logOrderIdAndSubtaskMap, dictValueAndDictResDtoMap);
+                            tradeIdAndLogOrderList, logOrderIdAndSubtaskMap, waybillOrderIdAndTicketList, dictValueAndDictResDtoMap);
                 })
                 .filter(logisticsOrderResp -> {
                     // 校验是否满足车辆任务量,满足才保留
@@ -404,6 +406,7 @@ public class WaybillOrderService {
                                                      Map<Long, OrderDetailVo> tradeIdAndOrderDetailVoMap,
                                                      Map<Long, List<KwtLogisticsOrder>> tradeIdAndLogOrderList ,
                                                      Map<Long, List<KwtWaybillOrderSubtask>> logisticsOrderIdAndSubtaskList,
+                                                     Map<Long, List<KwtWaybillOrderTicket>> waybillOrderIdAndTicketList,
                                                      Map<String, Map<String, String>> dictValueAndDictResDtoMap) {
         LogisticsOrderResp orderResp = new LogisticsOrderResp();
         orderResp.setLogisticsOrderId(Optional.ofNullable(order.getId()).map(String::valueOf).orElse(null));
@@ -453,7 +456,8 @@ public class WaybillOrderService {
         orderResp.setStatus(Optional.ofNullable(order.getStatus()).map(String::valueOf).orElse(null));
         orderResp.setStatusDesc(LogisticsOrderV1Enum.IN_TRANSIT.getCode().equals(order.getStatus()) ? "待接单" : "未知状态");
         //设置余量
-        BigDecimal orderSurplus = getSupAmount(order.getTOrderId(), tradeIdAndOrderDetailVoMap, tradeIdAndLogOrderList, logisticsOrderIdAndSubtaskList);
+        BigDecimal orderSurplus = getSupAmount(order.getTOrderId(), tradeIdAndOrderDetailVoMap, tradeIdAndLogOrderList,
+                logisticsOrderIdAndSubtaskList, waybillOrderIdAndTicketList);
         orderResp.setOrderSurplus(orderSurplus.toPlainString());
         orderResp.setRemainingAmount(orderSurplus);
 
@@ -758,6 +762,8 @@ public class WaybillOrderService {
                 .collect(Collectors.groupingBy(KwtLogisticsOrder::getTOrderId));
         Map<Long, List<KwtWaybillOrderSubtask>> logisticsOrderIdAndSubtaskList = orderSubtaskList.stream()
                 .collect(Collectors.groupingBy(KwtWaybillOrderSubtask::getLOrderId));
+        // 预加载运单磅单信息,避免在余量计算中出现 N+1 查询
+        Map<Long, List<KwtWaybillOrderTicket>> waybillOrderIdAndTicketList = getWaybillOrderIdAndTicketList(orderSubtaskList);
         //物流订单商品
         List<KwtLogisticsOrderGoods> logOrderGoods = logisticsOrderGoodsRepository.queryByLogOrderIds(logOrderIdList);
         if (CollectionUtils.isEmpty(logOrderGoods)) {
@@ -807,7 +813,8 @@ public class WaybillOrderService {
                 billOrder -> {
                     return getWaybillOrderResp(billOrder, subtaskMap, logOrderMap, logOrderIdAndCirculateMap,
                             logOrderIdAndGoodsMap, logOrderIdAndUnitMap, logOrderIdAndAddressMap, ticketMap,
-                            tradeIdAndOrderDetailVoMap,tradeIdAndLogOrderList,logisticsOrderIdAndSubtaskList,dictValueAndDictResDtoMap, goodsIdAndGoodsMap);
+                            tradeIdAndOrderDetailVoMap,tradeIdAndLogOrderList,logisticsOrderIdAndSubtaskList,
+                            waybillOrderIdAndTicketList,dictValueAndDictResDtoMap, goodsIdAndGoodsMap);
                 }).collect(Collectors.toList());
         return ordderList;
     }
@@ -831,6 +838,7 @@ public class WaybillOrderService {
                                                        Map<Long, OrderDetailVo> tradeIdAndOrderDetailVoMap,
                                                        Map<Long, List<KwtLogisticsOrder>> tradeIdAndLogOrderList ,
                                                        Map<Long, List<KwtWaybillOrderSubtask>> logisticsOrderIdAndSubtaskList,
+                                                       Map<Long, List<KwtWaybillOrderTicket>> waybillOrderIdAndTicketList,
                                                        Map<String, Map<String, String>> dictValueAndDictResDtoMap,
                                                        Map<Long, KwpGoods> goodsIdAndGoodsMap) {
         WaybillOrderStatusResp wbOrderResp = new WaybillOrderStatusResp();
@@ -850,7 +858,8 @@ public class WaybillOrderService {
         wbOrderResp.setChargeTypeDesc(DictEnum.getLabel(DictTypeEnum.CHARGING_TYPE.getType(), logOrder.getBillingMode()));
         //设置余量
         KwtLogisticsOrder order = logOrderMap.getOrDefault(wbOrder.getLOrderId(), new KwtLogisticsOrder());
-        BigDecimal supAmount = getSupAmount(order.getTOrderId(), tradeIdAndOrderDetailVoMap, tradeIdAndLogOrderList, logisticsOrderIdAndSubtaskList);
+        BigDecimal supAmount = getSupAmount(order.getTOrderId(), tradeIdAndOrderDetailVoMap, tradeIdAndLogOrderList,
+                logisticsOrderIdAndSubtaskList, waybillOrderIdAndTicketList);
         wbOrderResp.setOrderSurplus(supAmount);
         //托运企业
         KwtLogisticsOrderUnit consignEnt = logOrderIdAndUnitMap.getOrDefault(wbOrder.getLOrderId() + "-" + UnitTypeEnum.CONSIGN.getCode(), new KwtLogisticsOrderUnit());
@@ -925,47 +934,137 @@ public class WaybillOrderService {
 
     }
 
-    private static BigDecimal getSupAmount(Long tradeOrderId,
-                                       Map<Long, OrderDetailVo> tradeIdAndOrderDetailVoMap,
-                                       Map<Long, List<KwtLogisticsOrder>> tradeIdAndLogOrderList,
-                                       Map<Long, List<KwtWaybillOrderSubtask>> logisticsOrderIdAndSubtaskList) {
-       // KwtLogisticsOrder order = logOrderMap.getOrDefault(wbOrder.getLOrderId(), new KwtLogisticsOrder());
+    /**
+     * 计算贸易订单余量
+     * 逻辑:贸易订单总量 - (所有关联物流订单下,非取消/完成状态的子运单委托量 + 对应计费模式的磅单量)
+     *
+     * @param tradeOrderId                贸易订单ID
+     * @param tradeIdAndOrderDetailVoMap  贸易订单详情映射
+     * @param tradeIdAndLogOrderList      贸易订单关联的物流订单列表映射
+     * @param logisticsOrderIdAndSubtaskList 物流订单关联的子运单列表映射
+     * @param waybillOrderIdAndTicketList    运单ID关联的磅单列表映射
+     * @return 订单余量,保留两位小数
+     */
+    private BigDecimal getSupAmount(Long tradeOrderId,
+                                    Map<Long, OrderDetailVo> tradeIdAndOrderDetailVoMap,
+                                    Map<Long, List<KwtLogisticsOrder>> tradeIdAndLogOrderList,
+                                    Map<Long, List<KwtWaybillOrderSubtask>> logisticsOrderIdAndSubtaskList,
+                                    Map<Long, List<KwtWaybillOrderTicket>> waybillOrderIdAndTicketList) {
+        log.debug("开始计算贸易订单余量,tradeOrderId: {}", tradeOrderId);
+
+        // 1. 获取贸易订单总货物量
         OrderDetailVo detailVo = tradeIdAndOrderDetailVoMap.getOrDefault(tradeOrderId, new OrderDetailVo());
         BigDecimal tradeAmount = Optional.ofNullable(detailVo).map(OrderDetailVo::getAmount).orElse(BigDecimal.ZERO);
+        log.debug("贸易订单[{}]总货物量: {}", tradeOrderId, tradeAmount);
+
+        // 2. 获取该贸易订单下的所有物流订单
         List<KwtLogisticsOrder> kwtLogisticsOrders = tradeIdAndLogOrderList.get(tradeOrderId);
-        BigDecimal logTotatalAmount = BigDecimal.ZERO;
-        if (CollectionUtils.isNotEmpty(kwtLogisticsOrders)){
-            String billingMode = kwtLogisticsOrders.get(0).getBillingMode();
+        
+        // 已占用总量初始化
+        BigDecimal usedAmount = BigDecimal.ZERO;
 
+        if (CollectionUtils.isNotEmpty(kwtLogisticsOrders)) {
+            log.debug("贸易订单[{}]关联物流订单数量: {}", tradeOrderId, kwtLogisticsOrders.size());
+            
             for (KwtLogisticsOrder kwtLogisticsOrder : kwtLogisticsOrders) {
-                List<KwtWaybillOrderSubtask> waybillOrderSubtasks = logisticsOrderIdAndSubtaskList.getOrDefault(kwtLogisticsOrder.getId(), new ArrayList<>());
-                BigDecimal loadAmountSum = waybillOrderSubtasks.stream()
-                        .filter(x->!Arrays.asList(CarWaybillV1Enum.COMPLETED.getCode(), CarWaybillV1Enum.CANCELLED.getCode()).contains(x.getStatus()))
+                Long logOrderId = kwtLogisticsOrder.getId();
+                // 获取当前物流订单下的所有子运单
+                List<KwtWaybillOrderSubtask> waybillOrderSubtasks = logisticsOrderIdAndSubtaskList.getOrDefault(logOrderId, Collections.emptyList());
+                
+                if (CollectionUtils.isEmpty(waybillOrderSubtasks)) {
+                    log.debug("物流订单[{}]无子运单,跳过", logOrderId);
+                    continue;
+                }
+
+                // 3. 确定计费模式对应的磅单类型
+                // CHARGING_TYPE_1: 按装货量计费 -> 取装货磅单 (SHIPMENT)
+                // CHARGING_TYPE_2: 按卸货量计费 -> 取卸货磅单 (TAKE)
+                Integer ticketType;
+                String billingMode = kwtLogisticsOrder.getBillingMode();
+                if (StringUtils.equals(billingMode, DictEnum.CHARGING_TYPE_1.getValue())) {
+                    ticketType = AddressTypeEnum.SHIPMENT.getCode();
+                } else if (StringUtils.equals(billingMode, DictEnum.CHARGING_TYPE_2.getValue())) {
+                    ticketType = AddressTypeEnum.TAKE.getCode();
+                } else {
+                    log.warn("余量计算跳过未知计费模式,tradeOrderId:{}, logOrderId:{}, billingMode:{}",
+                            tradeOrderId, logOrderId, billingMode);
+                    continue;
+                }
+
+                // 定义需要剔除的状态:已取消、已完成(这些状态下的运单不再占用当前可接单的余量,或者其量已结算)
+                // 注意:具体业务逻辑中,通常“进行中”的运单会占用余量。这里根据原代码逻辑,剔除CANCELLED和COMPLETED。
+                List<Integer> excludeStatusList = Arrays.asList(CarWaybillV1Enum.CANCELLED.getCode(), CarWaybillV1Enum.COMPLETED.getCode());
+
+                // 4. 计算子运单委托量合计(仅统计未取消/未完成的有效子运单)
+                BigDecimal entrustAmount = waybillOrderSubtasks.stream()
+                        .filter(Objects::nonNull)
+                        .filter(subtask -> !excludeStatusList.contains(subtask.getStatus()))
                         .map(KwtWaybillOrderSubtask::getEntrustAmount)
                         .filter(Objects::nonNull)
                         .reduce(BigDecimal.ZERO, BigDecimal::add);
-                if (org.apache.commons.lang3.StringUtils.equals(billingMode, DictEnum.CHARGING_TYPE_1.getValue())){
-                    BigDecimal unloadAmountSum = waybillOrderSubtasks.stream()
-                            .filter(x->!Objects.equals(x.getStatus(),CarWaybillV1Enum.CANCELLED.getCode()))
-                            .map(KwtWaybillOrderSubtask::getLoadAmount)
-                            .filter(Objects::nonNull)
-                            .reduce(BigDecimal.ZERO, BigDecimal::add);
-                    logTotatalAmount = logTotatalAmount.add(loadAmountSum).add(unloadAmountSum);
-                }else if (org.apache.commons.lang3.StringUtils.equals(billingMode, DictEnum.CHARGING_TYPE_2.getValue())){
-                    BigDecimal unloadAmountSum = waybillOrderSubtasks.stream()
-                            .filter(x->!Objects.equals(x.getStatus(),CarWaybillV1Enum.CANCELLED.getCode()))
-                            .map(KwtWaybillOrderSubtask::getUnloadAmount)
-                            .filter(Objects::nonNull)
-                            .reduce(BigDecimal.ZERO, BigDecimal::add);
-                    logTotatalAmount = logTotatalAmount.add(loadAmountSum).add(unloadAmountSum);
-                }
+                
+                log.debug("物流订单[{}]子运单委托量合计: {}", logOrderId, entrustAmount);
 
-                //logTotatalAmount = logTotatalAmount.add(unloadAmountSum);
+                // 5. 计算磅单量合计
+                // 逻辑:通过子运单找到关联的运单ID,再找到对应的磅单,过滤出指定类型(装/卸)的磅单量
+                BigDecimal ticketAmount = waybillOrderSubtasks.stream()
+                        .filter(Objects::nonNull)
+                        .filter(subtask -> !Objects.equals(subtask.getStatus(), CarWaybillV1Enum.CANCELLED.getCode()))
+                        .map(KwtWaybillOrderSubtask::getWOrderId)
+                        .filter(Objects::nonNull)
+                        // 展开每个运单ID对应的磅单列表
+                        .flatMap(wOrderId -> waybillOrderIdAndTicketList.getOrDefault(wOrderId, Collections.emptyList()).stream())
+                        .filter(Objects::nonNull)
+                        // 只保留符合计费模式的磅单类型(装货或卸货)
+                        .filter(ticket -> Objects.equals(ticket.getType(), ticketType))
+                        .map(KwtWaybillOrderTicket::getAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+                log.debug("物流订单[{}]磅单量合计(type:{}): {}", logOrderId, ticketType, ticketAmount);
+
+                // 累加到总占用量
+                usedAmount = usedAmount.add(entrustAmount).add(ticketAmount);
             }
         }
 
-        BigDecimal subSurplus = tradeAmount.subtract(logTotatalAmount).compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : tradeAmount.subtract(logTotatalAmount);
-        return subSurplus.setScale(2, RoundingMode.HALF_UP);
+        log.debug("贸易订单[{}]总占用量: {}", tradeOrderId, usedAmount);
+
+        // 6. 计算余量:贸易订单总量 - 已占用量
+        // 如果计算结果小于等于0,则余量为0,避免负数
+        BigDecimal surplus = tradeAmount.subtract(usedAmount);
+        BigDecimal finalSurplus = surplus.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : surplus;
+        
+        // 保留两位小数,四舍五入
+        BigDecimal result = finalSurplus.setScale(2, RoundingMode.HALF_UP);
+        log.debug("贸易订单[{}]最终余量: {}", tradeOrderId, result);
+        
+        return result;
+    }
+
+    /**
+     * 批量构建运单ID与磅单信息映射,供订单余量计算复用。
+     */
+    private Map<Long, List<KwtWaybillOrderTicket>> getWaybillOrderIdAndTicketList(List<KwtWaybillOrderSubtask> orderSubtaskList) {
+        if (CollectionUtils.isEmpty(orderSubtaskList)) {
+            return Collections.emptyMap();
+        }
+        List<Long> waybillOrderIds = orderSubtaskList.stream()
+                .filter(Objects::nonNull)
+                .map(KwtWaybillOrderSubtask::getWOrderId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(waybillOrderIds)) {
+            return Collections.emptyMap();
+        }
+        List<KwtWaybillOrderTicket> ticketList = waybillOrderTicketRepository.queryByWOrderIds(waybillOrderIds);
+        if (CollectionUtils.isEmpty(ticketList)) {
+            return Collections.emptyMap();
+        }
+        return ticketList.stream()
+                .filter(Objects::nonNull)
+                .collect(Collectors.groupingBy(KwtWaybillOrderTicket::getWOrderId));
     }
 
     /**