|
|
@@ -1,15 +1,18 @@
|
|
|
package com.sckw.transport.service.dashboard;
|
|
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import com.sckw.core.common.enums.enums.DictEnum;
|
|
|
import com.sckw.core.model.constant.Global;
|
|
|
import com.sckw.core.model.enums.CarWaybillV1Enum;
|
|
|
import com.sckw.core.utils.CollectionUtils;
|
|
|
import com.sckw.transport.api.model.vo.RealtimeSalesGoodsSeriesVo;
|
|
|
import com.sckw.transport.api.model.vo.RealtimeSalesVolumeVo;
|
|
|
+import com.sckw.transport.model.KwtLogisticsOrder;
|
|
|
import com.sckw.transport.model.KwtLogisticsOrderGoods;
|
|
|
import com.sckw.transport.model.KwtWaybillOrder;
|
|
|
import com.sckw.transport.model.KwtWaybillOrderSubtask;
|
|
|
import com.sckw.transport.repository.KwtLogisticsOrderGoodsRepository;
|
|
|
+import com.sckw.transport.repository.KwtLogisticsOrderRepository;
|
|
|
import com.sckw.transport.repository.KwtWaybillOrderRepository;
|
|
|
import com.sckw.transport.repository.KwtWaybillOrderSubtaskRepository;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
@@ -68,6 +71,7 @@ public class RealtimeSalesVolumeService {
|
|
|
private final KwtWaybillOrderRepository waybillOrderRepository;
|
|
|
private final KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
|
|
|
private final KwtLogisticsOrderGoodsRepository logisticsOrderGoodsRepository;
|
|
|
+ private final KwtLogisticsOrderRepository logisticsOrderRepository;
|
|
|
|
|
|
/**
|
|
|
* 构建实时销量视图对象
|
|
|
@@ -117,13 +121,16 @@ public class RealtimeSalesVolumeService {
|
|
|
// 5. 提取运单ID和物流订单ID集合,用于后续关联查询
|
|
|
Set<Long> wIds = waybills.stream().map(KwtWaybillOrder::getId).filter(Objects::nonNull).collect(Collectors.toSet());
|
|
|
Set<Long> lOrderIds = waybills.stream().map(KwtWaybillOrder::getLOrderId).filter(Objects::nonNull).collect(Collectors.toSet());
|
|
|
+ // 按物流订单计费方式决定净重取装货量还是卸货量,避免实时销量口径与结算口径不一致。
|
|
|
+ Map<Long, String> billingModeByLogOrder = billingModeByLogOrder(lOrderIds);
|
|
|
|
|
|
// 6. 查询运单子任务,并计算每个运单的净重总和
|
|
|
Map<Long, BigDecimal> netByWaybill = netWeightByWaybill(
|
|
|
waybillOrderSubtaskRepository.list(
|
|
|
Wrappers.<KwtWaybillOrderSubtask>lambdaQuery()
|
|
|
.in(KwtWaybillOrderSubtask::getWOrderId, wIds)
|
|
|
- .eq(KwtWaybillOrderSubtask::getDelFlag, Global.NO)));
|
|
|
+ .eq(KwtWaybillOrderSubtask::getDelFlag, Global.NO)),
|
|
|
+ billingModeByLogOrder);
|
|
|
log.debug("计算得到 {} 个运单的净重数据", netByWaybill.size());
|
|
|
|
|
|
// 7. 查询物流订单货物信息,并选取每个物流订单的主要商品
|
|
|
@@ -233,6 +240,29 @@ public class RealtimeSalesVolumeService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 查询物流订单计费方式映射。
|
|
|
+ *
|
|
|
+ * @param lOrderIds 物流订单ID集合
|
|
|
+ * @return 物流订单ID -> 计费方式
|
|
|
+ */
|
|
|
+ private Map<Long, String> billingModeByLogOrder(Set<Long> lOrderIds) {
|
|
|
+ if (CollectionUtils.isEmpty(lOrderIds)) {
|
|
|
+ log.debug("物流订单ID集合为空,跳过计费方式查询。");
|
|
|
+ return Map.of();
|
|
|
+ }
|
|
|
+ List<KwtLogisticsOrder> logisticsOrders = logisticsOrderRepository.queryByLogOrderIds(lOrderIds);
|
|
|
+ if (CollectionUtils.isEmpty(logisticsOrders)) {
|
|
|
+ log.warn("未查询到物流订单计费方式,lOrderIds={}", lOrderIds);
|
|
|
+ return Map.of();
|
|
|
+ }
|
|
|
+ Map<Long, String> result = logisticsOrders.stream()
|
|
|
+ .filter(order -> order != null && order.getId() != null && order.getBillingMode() != null)
|
|
|
+ .collect(Collectors.toMap(KwtLogisticsOrder::getId, KwtLogisticsOrder::getBillingMode, (left, right) -> left));
|
|
|
+ log.debug("物流订单计费方式映射构建完成,共 {} 条。", result.size());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 获取运单的完成时间
|
|
|
* <p>
|
|
|
@@ -257,15 +287,16 @@ public class RealtimeSalesVolumeService {
|
|
|
* @param subtasks 运单子任务列表
|
|
|
* @return 运单ID -> 净重总和的映射
|
|
|
*/
|
|
|
- private static Map<Long, BigDecimal> netWeightByWaybill(List<KwtWaybillOrderSubtask> subtasks) {
|
|
|
+ private static Map<Long, BigDecimal> netWeightByWaybill(List<KwtWaybillOrderSubtask> subtasks, Map<Long, String> billingModeByLogOrder) {
|
|
|
if (CollectionUtils.isEmpty(subtasks)) {
|
|
|
return Map.of();
|
|
|
}
|
|
|
|
|
|
Map<Long, BigDecimal> result = subtasks.stream()
|
|
|
+ .filter(st -> st != null && st.getWOrderId() != null)
|
|
|
.collect(Collectors.groupingBy(
|
|
|
KwtWaybillOrderSubtask::getWOrderId,
|
|
|
- Collectors.mapping(RealtimeSalesVolumeService::subtaskNetTon,
|
|
|
+ Collectors.mapping(st -> subtaskNetTon(st, billingModeByLogOrder.get(st.getLOrderId())),
|
|
|
Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
|
|
|
|
|
|
log.debug("从 {} 条子任务记录中聚合出 {} 个运单的净重。", subtasks.size(), result.size());
|
|
|
@@ -275,22 +306,31 @@ public class RealtimeSalesVolumeService {
|
|
|
/**
|
|
|
* 计算单个子任务的净重
|
|
|
* <p>
|
|
|
- * 优先使用卸货量 (unloadAmount),如果不存在或<=0,则尝试使用装货量 (loadAmount)。
|
|
|
+ * billingMode=1 按装货量计算,billingMode=2 按卸货量计算,其它缺失或异常值默认按卸货量计算。
|
|
|
*
|
|
|
* @param st 子任务对象
|
|
|
+ * @param billingMode 物流订单计费方式
|
|
|
* @return 净重(吨),默认为0
|
|
|
*/
|
|
|
- private static BigDecimal subtaskNetTon(KwtWaybillOrderSubtask st) {
|
|
|
+ static BigDecimal subtaskNetTon(KwtWaybillOrderSubtask st, String billingMode) {
|
|
|
if (st == null) {
|
|
|
return BigDecimal.ZERO;
|
|
|
}
|
|
|
-
|
|
|
- // 尝试获取卸货量,若无效则获取装货量
|
|
|
+ if (DictEnum.CHARGING_TYPE_1.getValue().equals(billingMode)) {
|
|
|
+ return validAmountOrZero(st.getLoadAmount());
|
|
|
+ }
|
|
|
+ return validAmountOrZero(st.getUnloadAmount());
|
|
|
+ }
|
|
|
|
|
|
- return Stream.of(st.getUnloadAmount(), st.getLoadAmount())
|
|
|
- .filter(Objects::nonNull)
|
|
|
- .filter(a -> a.compareTo(BigDecimal.ZERO) > 0) // 只取正数
|
|
|
- .findFirst()
|
|
|
+ /**
|
|
|
+ * 过滤无效重量,避免空指针和负数污染统计结果。
|
|
|
+ *
|
|
|
+ * @param amount 原始重量
|
|
|
+ * @return 有效重量;为空或小于等于0时返回0
|
|
|
+ */
|
|
|
+ private static BigDecimal validAmountOrZero(BigDecimal amount) {
|
|
|
+ return Optional.ofNullable(amount)
|
|
|
+ .filter(value -> value.compareTo(BigDecimal.ZERO) > 0)
|
|
|
.orElse(BigDecimal.ZERO);
|
|
|
}
|
|
|
|