chenxiaofei 1 месяц назад
Родитель
Сommit
1d01616f27

+ 22 - 0
sckw-modules-api/sckw-transport-api/src/main/java/com/sckw/transport/api/dubbo/TransportRemoteStatisticsService.java

@@ -1,5 +1,7 @@
 package com.sckw.transport.api.dubbo;
 
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.List;
 
 /**
@@ -43,4 +45,24 @@ public interface TransportRemoteStatisticsService {
      */
     Integer statisticsPendingVerificationWaybill(Long topEntId);
 
+    /**
+     * 统计贸易订单已派车次,排除已取消运单。
+     *
+     * @param tradeOrderId 贸易订单ID
+     * @return 已派车次数
+     */
+    Long countDispatchedWaybillsByTradeOrderId(Long tradeOrderId);
+
+    /**
+     * 按时间范围汇总贸易订单已完成运单的完成量。
+     *
+     * @param tradeOrderId 贸易订单ID
+     * @param chargeType 计费方式:1-装货量,2-卸货量
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @return 完成量
+     */
+    BigDecimal sumCompletedWaybillVolumeByTimeRange(Long tradeOrderId, Integer chargeType,
+                                                    LocalDateTime startTime, LocalDateTime endTime);
+
 }

+ 9 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/controller/KwoTradeOrderController.java

@@ -134,6 +134,15 @@ public class KwoTradeOrderController {
         return HttpResult.ok("贸易订单详情查询成功", kwoTradeOrderService.getDetail(id));
     }
 
+    /**
+     * 贸易订单详情看板:完成率、今日/本月运单完成量、派车次数
+     */
+    @GetMapping("/dashboardStatistic")
+    @Operation(summary = "贸易订单看板统计", description = "完成率、今日总量、车次、本月总量")
+    public HttpResult dashboardStatistic(@RequestParam Long id) {
+        return HttpResult.ok("查询成功", kwoTradeOrderService.tradeOrderDashboardStatistic(id));
+    }
+
     @PostMapping("/audit")
     @Operation(summary = "审核贸易订单", description = "审核贸易订单")
 //    @GlobalTransactional(name = "default_tx_group")

+ 1 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/dao/KwoTradeOrderMapper.java

@@ -160,4 +160,5 @@ public interface KwoTradeOrderMapper extends BaseMapper<KwoTradeOrder> {
     List<GoodsVo> countGoods(@Param("para") CountPara countPara, @Param("ids") List<Long> ids);
 
     List<TradeBuyVo> buyRank(@Param("para") CountPara countPara, @Param("ids") List<Long> ids);
+
 }

+ 37 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/model/vo/res/TradeOrderDashboardVO.java

@@ -0,0 +1,37 @@
+package com.sckw.order.model.vo.res;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 贸易订单详情页看板统计(完成率、今日/本月完成量、车次)
+ */
+@Getter
+@Setter
+@ToString
+@Accessors(chain = true)
+@Schema(description = "贸易订单看板统计")
+public class TradeOrderDashboardVO implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "完成率(%),已完成量/订单总量*100,保留两位小数")
+    private BigDecimal completionRate;
+
+    @Schema(description = "今日完成量(吨),按计费方式取装货量或审核后卸货量")
+    private BigDecimal todayTotalVolume;
+
+    @Schema(description = "已派车次数(非已取消运单数)")
+    private Long tripCount;
+
+    @Schema(description = "本月完成量(吨),按计费方式取装货量或审核后卸货量")
+    private BigDecimal monthTotalVolume;
+}

+ 105 - 8
sckw-modules/sckw-order/src/main/java/com/sckw/order/serivce/KwoTradeOrderService.java

@@ -54,6 +54,7 @@ import com.sckw.order.model.vo.res.OrderDetailRes;
 import com.sckw.order.model.vo.res.UnitInfoDetailRes;
 import com.sckw.order.model.vo.res.*;
 import com.sckw.order.repository.KwoTradeOrderUnitRepository;
+import com.sckw.order.util.TradeOrderDashboardUtils;
 import com.sckw.payment.api.dubbo.PayCenterDubboService;
 import com.sckw.payment.api.dubbo.PaymentDubboService;
 import com.sckw.payment.api.feign.PaymentFeignService;
@@ -78,6 +79,7 @@ import com.sckw.system.api.feign.DataPermissionFeignService;
 import com.sckw.system.api.model.dto.req.ActualDisPatchDto;
 import com.sckw.system.api.model.dto.req.DataPermissionFilterReqDto;
 import com.sckw.system.api.model.dto.res.*;
+import com.sckw.transport.api.dubbo.TransportRemoteStatisticsService;
 import com.sckw.transport.api.dubbo.TransportRemoteService;
 import com.sckw.transport.api.model.param.AddLogisticOrderParam;
 import com.sckw.transport.api.model.param.LogisticInfo;
@@ -97,7 +99,10 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.temporal.TemporalAdjusters;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
@@ -136,6 +141,9 @@ public class KwoTradeOrderService {
     @DubboReference(version = "1.0.0", group = "design", check = false)
     private TransportRemoteService transportRemoteService;
 
+    @DubboReference(version = "1.0.0", group = "design", check = false)
+    private TransportRemoteStatisticsService transportRemoteStatisticsService;
+
     @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
     protected RemoteFleetService remoteFleetService;
 
@@ -666,6 +674,7 @@ public class KwoTradeOrderService {
         List<OrderProcess> orderProcesses = new ArrayList<>(tracks.size());
         List<Long> createBys = tracks.stream().map(KwoTradeOrderTrack::getCreateBy).distinct().toList();
         Map<Long, UserCacheResDto> map = remoteSystemService.queryUserCacheMapByIds(createBys);
+        List<Integer> statusList = Arrays.asList(TradeOrderStatusEnum.AUDIT.getCode(), TradeOrderStatusEnum.ING.getCode(), TradeOrderStatusEnum.DEAL.getCode());
         tracks.forEach(e -> {
             OrderProcess process = BeanUtil.copyProperties(e, OrderProcess.class);
             UserCacheResDto user = map.get(process.getCreateBy());
@@ -676,10 +685,22 @@ public class KwoTradeOrderService {
                     process.setRoleName(String.join(",", roleNames));
                 }
             }
-            process.setStatusLabel(OrderStatusEnum.getMsg(process.getStatus()));
-            orderProcesses.add(process);
+            if (statusList.contains(process.getStatus())){
+                if (Objects.equals(process.getStatus(),TradeOrderStatusEnum.AUDIT.getCode())){
+                    process.setStatusLabel("订单创建");
+                }
+                if (Objects.equals(process.getStatus(),TradeOrderStatusEnum.ING.getCode())){
+                    process.setStatusLabel("审核");
+                }
+                if (Objects.equals(process.getStatus(),TradeOrderStatusEnum.DEAL.getCode())){
+                    process.setStatusLabel("结算");
+                }
+                orderProcesses.add(process);
+            }
         });
-        detail.setOrderProcess(orderProcesses);
+        List<OrderProcess> orderProcesses1 = orderProcesses.stream().sorted(Comparator.comparing(OrderProcess::getCreateTime).reversed()).collect(Collectors.toList());
+
+        detail.setOrderProcess(orderProcesses1);
         return detail;
     }
 
@@ -1875,6 +1896,86 @@ public class KwoTradeOrderService {
         return statistics;
     }
 
+    /**
+     * 贸易订单详情看板:完成率、今日/本月完成量、已派车次数(与贸易订单关联运单,按计费方式统计装卸货量)
+     *
+     * @param tOrderId 贸易订单主键
+     * @return 看板数据
+     */
+    public TradeOrderDashboardVO tradeOrderDashboardStatistic(Long tOrderId) {
+        if (Objects.isNull(tOrderId) || tOrderId <= 0) {
+            throw new BusinessException("贸易订单主键不能为空");
+        }
+        KwoTradeOrder order = kwoTradeOrderMapper.selectById(tOrderId);
+        if (order == null) {
+            throw new BusinessException("不存在该订单!");
+        }
+        ZoneId zone = ZoneId.of("Asia/Shanghai");
+        LocalDate today = LocalDate.now(zone);
+        LocalDateTime dayStart = today.atStartOfDay();
+        LocalDateTime dayEnd = dayStart.plusDays(1);
+        LocalDateTime monthStart = today.with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay();
+        LocalDateTime monthEnd = monthStart.plusMonths(1);
+
+        BigDecimal completionRate = TradeOrderDashboardUtils.completionRateOf(order);
+        Long tripCount = getDispatchedWaybillCount(tOrderId);
+
+        Integer chargeType = order.getChargeType();
+        BigDecimal todayVol = BigDecimal.ZERO;
+        BigDecimal monthVol = BigDecimal.ZERO;
+        if (Objects.equals(chargeType, ChargingTypeEnum.ON.getCode())
+                || Objects.equals(chargeType, ChargingTypeEnum.OFF.getCode())) {
+            todayVol = getCompletedWaybillVolume(tOrderId, chargeType, dayStart, dayEnd);
+            monthVol = getCompletedWaybillVolume(tOrderId, chargeType, monthStart, monthEnd);
+        }
+        todayVol = todayVol.setScale(2, RoundingMode.HALF_UP);
+        monthVol = monthVol.setScale(2, RoundingMode.HALF_UP);
+
+        return new TradeOrderDashboardVO()
+                .setCompletionRate(completionRate)
+                .setTodayTotalVolume(todayVol)
+                .setTripCount(tripCount)
+                .setMonthTotalVolume(monthVol);
+    }
+
+    /**
+     * 获取贸易订单已派车次。
+     *
+     * @param tOrderId 贸易订单ID
+     * @return 已派车次数
+     */
+    private Long getDispatchedWaybillCount(Long tOrderId) {
+        try {
+            return Optional.ofNullable(transportRemoteStatisticsService.countDispatchedWaybillsByTradeOrderId(tOrderId))
+                    .orElse(0L);
+        } catch (Exception e) {
+            log.error("查询贸易订单已派车次失败,tOrderId={}", tOrderId, e);
+            throw new BusinessException("查询贸易订单已派车次失败");
+        }
+    }
+
+    /**
+     * 获取贸易订单指定时间范围内的运单完成量。
+     *
+     * @param tOrderId 贸易订单ID
+     * @param chargeType 计费方式
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @return 运单完成量
+     */
+    private BigDecimal getCompletedWaybillVolume(Long tOrderId, Integer chargeType,
+                                                 LocalDateTime startTime, LocalDateTime endTime) {
+        try {
+            return Optional.ofNullable(transportRemoteStatisticsService.sumCompletedWaybillVolumeByTimeRange(
+                            tOrderId, chargeType, startTime, endTime))
+                    .orElse(BigDecimal.ZERO);
+        } catch (Exception e) {
+            log.error("查询贸易订单运单完成量失败,tOrderId={}, chargeType={}, startTime={}, endTime={}",
+                    tOrderId, chargeType, startTime, endTime, e);
+            throw new BusinessException("查询贸易订单运单完成量失败");
+        }
+    }
+
     /**
      * @desc: 贸易订单列表导出
      * @author: yzc
@@ -2273,11 +2374,7 @@ public class KwoTradeOrderService {
         if (!Objects.equals(order.getStatus(), TradeOrderStatusEnum.AUDIT.getCode())) {
             throw new BusinessException("当前订单状态不允许撤销");
         }
-        KwoTradeOrderContract byOrderId = kwoTradeOrderContractService.getByOrderId(param.getTradeContractId());
-        if (Objects.isNull(byOrderId)) {
-            throw new BusinessException("贸易合同不存在");
-        }
-        TradeContractResDto tradeContractResDto = remoteContractService.queryTradeContract(byOrderId.getContractId(), param.getGoodsId());
+        TradeContractResDto tradeContractResDto = remoteContractService.queryTradeContract(param.getTradeContractId(), param.getGoodsId());
         // 1. 线下钱包加回预付余额、减冻结金额
         List<TradeContractUnitDto> unitList = tradeContractResDto.getUnitList();
         WalletPrepaidDto freezeDto = new WalletPrepaidDto();

+ 51 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/util/TradeOrderDashboardUtils.java

@@ -0,0 +1,51 @@
+package com.sckw.order.util;
+
+import com.sckw.core.model.enums.ChargingTypeEnum;
+import com.sckw.order.model.KwoTradeOrder;
+import org.springframework.lang.Nullable;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * 贸易订单看板统计用计算工具(完成率等)
+ */
+public final class TradeOrderDashboardUtils {
+
+    private static final BigDecimal HUNDRED = new BigDecimal("100");
+
+    private TradeOrderDashboardUtils() {
+    }
+
+    /**
+     * 完成率 = 已完成量 / 订单货物总量(吨等) * 100,四舍五入保留两位小数。
+     * 装货量结算取累计装货量;卸货量结算取累计卸货量;按车次计费取实际交付量;总量为空或小于等于0时返回0.
+     */
+    public static BigDecimal completionRateOf(@Nullable KwoTradeOrder order) {
+        if (order == null) {
+            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
+        }
+        BigDecimal total = order.getAmount();
+        if (total == null || total.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
+        }
+        Integer chargeType = order.getChargeType();
+        BigDecimal done;
+        if (Objects.equals(chargeType, ChargingTypeEnum.ON.getCode())) {
+            done = Optional.ofNullable(order.getLoadAmount()).orElse(BigDecimal.ZERO);
+        } else if (Objects.equals(chargeType, ChargingTypeEnum.OFF.getCode())) {
+            done = Optional.ofNullable(order.getUnloadAmount()).orElse(BigDecimal.ZERO);
+        } else if (Objects.equals(chargeType, ChargingTypeEnum.CAR.getCode())) {
+            done = Optional.ofNullable(order.getActualAmount()).orElse(BigDecimal.ZERO);
+        } else {
+            done = Optional.ofNullable(order.getActualAmount())
+                    .filter(a -> a.compareTo(BigDecimal.ZERO) > 0)
+                    .or(() -> Optional.ofNullable(order.getLoadAmount()))
+                    .or(() -> Optional.ofNullable(order.getUnloadAmount()))
+                    .orElse(BigDecimal.ZERO);
+        }
+        return done.multiply(HUNDRED).divide(total, 2, RoundingMode.HALF_UP);
+    }
+}

+ 23 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/dao/KwtLogisticsOrderMapper.java

@@ -16,6 +16,7 @@ import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -482,4 +483,26 @@ public interface KwtLogisticsOrderMapper extends BaseMapper<KwtLogisticsOrder> {
     Long queryCount(@Param("ids") List<Long> ids);
 
     List<LogisticsBaseOrderVo> selectBase(@Param("para")LogisticsOrderPara orderPara);
+
+    /**
+     * 统计贸易订单已派车次,排除已取消运单。
+     *
+     * @param tOrderId 贸易订单ID
+     * @return 已派车次数
+     */
+    Long countDispatchedWaybillsByTradeOrderId(@Param("tOrderId") Long tOrderId);
+
+    /**
+     * 按时间范围汇总贸易订单已完成运单的完成量。
+     *
+     * @param tOrderId 贸易订单ID
+     * @param chargeType 计费方式:1-装货量,2-卸货量
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @return 完成量
+     */
+    BigDecimal sumCompletedWaybillVolumeByTimeRange(@Param("tOrderId") Long tOrderId,
+                                                    @Param("chargeType") Integer chargeType,
+                                                    @Param("startTime") LocalDateTime startTime,
+                                                    @Param("endTime") LocalDateTime endTime);
 }

+ 42 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/dubbo/TransportStatisticsServiceImpl.java

@@ -1,6 +1,7 @@
 package com.sckw.transport.dubbo;
 
 import com.sckw.core.model.constant.NumberConstant;
+import com.sckw.core.exception.BusinessException;
 import com.sckw.core.model.enums.CarWaybillEnum;
 import com.sckw.core.model.enums.LogisticsOrderEnum;
 import com.sckw.transport.api.dubbo.TransportRemoteStatisticsService;
@@ -12,8 +13,12 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 /**
@@ -126,4 +131,41 @@ public class TransportStatisticsServiceImpl implements TransportRemoteStatistics
         Integer count = logisticsOrderMapper.statisticsLogisticsByTopEntIdAndOrderStatus(topEntId, orderList,"1",enterpriseIds);
         return count;
     }
+    /**
+     * 统计贸易订单已派车次。
+     *
+     * @param tradeOrderId 贸易订单ID
+     * @return 已派车次数
+     */
+    @Override
+    public Long countDispatchedWaybillsByTradeOrderId(Long tradeOrderId) {
+        if (Objects.isNull(tradeOrderId)) {
+            throw new BusinessException("贸易订单ID不能为空");
+        }
+        return Optional.ofNullable(logisticsOrderMapper.countDispatchedWaybillsByTradeOrderId(tradeOrderId))
+                .orElse(0L);
+    }
+
+    /**
+     * 按时间范围汇总贸易订单已完成运单的完成量。
+     *
+     * @param tradeOrderId 贸易订单ID
+     * @param chargeType 计费方式:1-装货量,2-卸货量
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @return 完成量
+     */
+    @Override
+    public BigDecimal sumCompletedWaybillVolumeByTimeRange(Long tradeOrderId, Integer chargeType,
+                                                           LocalDateTime startTime, LocalDateTime endTime) {
+        if (Objects.isNull(tradeOrderId)) {
+            throw new BusinessException("贸易订单ID不能为空");
+        }
+        if (Objects.isNull(chargeType)) {
+            throw new BusinessException("计费方式不能为空");
+        }
+        return Optional.ofNullable(logisticsOrderMapper.sumCompletedWaybillVolumeByTimeRange(
+                        tradeOrderId, chargeType, startTime, endTime))
+                .orElse(BigDecimal.ZERO);
+    }
 }

+ 44 - 0
sckw-modules/sckw-transport/src/main/resources/mapper/KwtLogisticsOrderMapper.xml

@@ -2160,6 +2160,50 @@
         </if>
     </select>
 
+    <select id="countDispatchedWaybillsByTradeOrderId" resultType="java.lang.Long">
+        SELECT COUNT(1)
+        FROM kwt_logistics_order lo
+                 INNER JOIN kwt_waybill_order wo ON wo.l_order_id = lo.id AND wo.del_flag = 0
+        WHERE lo.t_order_id = #{tOrderId}
+          AND lo.del_flag = 0
+          AND wo.status &lt;&gt; 99
+    </select>
+
+    <select id="sumCompletedWaybillVolumeByTimeRange" resultType="java.math.BigDecimal">
+        SELECT COALESCE(SUM(
+        <choose>
+            <when test="chargeType == 1">
+                wos.load_amount
+            </when>
+            <when test="chargeType == 2">
+                wos.unload_amount
+            </when>
+            <otherwise>
+                0
+            </otherwise>
+        </choose>
+        ), 0)
+        FROM kwt_logistics_order lo
+                 INNER JOIN kwt_waybill_order wo ON wo.l_order_id = lo.id AND wo.del_flag = 0
+                 INNER JOIN kwt_waybill_order_subtask wos ON wos.w_order_id = wo.id AND wos.del_flag = 0
+        WHERE lo.t_order_id = #{tOrderId}
+          AND lo.del_flag = 0
+          AND wo.status = 25
+        <if test="chargeType == 1">
+          AND wos.load_amount IS NOT NULL
+        </if>
+        <if test="chargeType == 2">
+          AND wos.unload_amount IS NOT NULL
+        </if>
+        <if test="chargeType == null or (chargeType != 1 and chargeType != 2)">
+          AND 1 = 0
+        </if>
+        <if test="startTime != null and endTime != null">
+          AND wo.update_time <![CDATA[ >= ]]> #{startTime}
+          AND wo.update_time <![CDATA[ < ]]> #{endTime}
+        </if>
+    </select>
+
     <select id="statisticsLogistics" resultType="java.lang.Long">
         SELECT DISTINCT a.id
         FROM kwt_logistics_order a