Przeglądaj źródła

司机app端接单业务流程开发

donglang 1 miesiąc temu
rodzic
commit
1ac0b08173
47 zmienionych plików z 3151 dodań i 98 usunięć
  1. 110 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/common/enums/enums/ErrorCodeEnum.java
  2. 48 0
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/exception/BusinessPlatfromException.java
  3. 0 3
      sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/constant/HttpStatus.java
  4. 4 0
      sckw-modules-api/sckw-fleet-api/src/main/java/com/sckw/fleet/api/RemoteFleetService.java
  5. 7 0
      sckw-modules-api/sckw-fleet-api/src/main/java/com/sckw/fleet/api/model/vo/RDriverVo.java
  6. 11 1
      sckw-modules-api/sckw-fleet-api/src/main/java/com/sckw/fleet/api/model/vo/RTruckVo.java
  7. 10 0
      sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/dubbo/TradeOrderInfoService.java
  8. 11 0
      sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/model/OrderDetailVo.java
  9. 23 2
      sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/dubbo/RemoteFleetServiceImpl.java
  10. 6 0
      sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/repository/KwfTruckRepository.java
  11. 20 0
      sckw-modules/sckw-order/src/main/java/com/sckw/order/dubbo/TradeOrderInfoServiceImpl.java
  12. 5 0
      sckw-modules/sckw-order/src/main/java/com/sckw/order/model/KwoTradeOrder.java
  13. 3 1
      sckw-modules/sckw-order/src/main/java/com/sckw/order/repository/KwoTradeOrderRepository.java
  14. 4 0
      sckw-modules/sckw-transport/pom.xml
  15. 79 6
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/controller/enterpriseApp/AppWayBillController.java
  16. 16 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/dao/KwtWaybillOrderNodeMapper.java
  17. 166 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/AbstractWaybillOrderHandler.java
  18. 78 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/BusinessContext.java
  19. 118 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/CancelHandler.java
  20. 83 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/ComeIntoHandler.java
  21. 61 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/LeaveHandler.java
  22. 115 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/LeaveMockHandler.java
  23. 51 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/LoadingHandler.java
  24. 496 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/TakingOrderHandler.java
  25. 67 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/UnloadingHandler.java
  26. 93 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/KwtWaybillOrderNode.java
  27. 5 41
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/KwtWaybillOrderTicket.java
  28. 0 2
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/OrderCirculateQueryParam.java
  29. 63 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/OrderCirculateTakingQueryParam.java
  30. 37 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderCancelParam.java
  31. 68 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderCmeIntoWeighParam.java
  32. 37 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderLeaveMockParam.java
  33. 51 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderLeaveParam.java
  34. 46 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderLoadingParam.java
  35. 44 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderProcessParam.java
  36. 67 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderUnloadParam.java
  37. 10 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtLogisticsOrderCirculateRepository.java
  38. 2 2
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtLogisticsOrderRepository.java
  39. 0 2
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderAddressRepository.java
  40. 15 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderNodeRepository.java
  41. 8 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderRepository.java
  42. 6 1
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderSubtaskRepository.java
  43. 24 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderTicketRepository.java
  44. 62 36
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/KwtLogisticsConsignmentService.java
  45. 2 1
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/KwtWaybillOrderV1Service.java
  46. 900 0
      sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/app/WaybillOrderService.java
  47. 19 0
      sql/2025/mvp2/2025_11_03_donglang.sql

+ 110 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/common/enums/enums/ErrorCodeEnum.java

@@ -0,0 +1,110 @@
+package com.sckw.core.common.enums.enums;
+
+import lombok.Getter;
+
+/**
+ *Author: donglang
+ *Time: 2025-10-09
+ *Description: 平台异常编码枚举,统一管理系统中的错误码和描述
+ *Version: 1.0
+ */
+@Getter
+public enum ErrorCodeEnum {
+
+    // ====================== 通用错误(10000~19999)======================
+    SYSTEM_ERROR("100000", "系统内部错误"),
+    PARAM_ERROR("100001", "参数校验失败"),
+    RESOURCE_NOT_FOUND("100002", "资源不存在"),
+    PERMISSION_DENIED("100003", "权限不足"),
+    NETWORK_ERROR("100004", "网络连接异常"),
+    DB_OPERATE_FAIL("100005", "数据库操作异常"),
+
+    // ====================== 设备相关错误(20000~29999)======================
+    DEVICE_OFFLINE("200000", "设备离线"),
+    DEVICE_ALREADY_EXIST("200001", "设备已存在"),
+    DEVICE_NOT_REGISTERED("200002", "设备未注册"),
+    DEVICE_DATA_FORMAT_ERROR("200003", "设备数据格式错误"),
+    DEVICE_COMMAND_TIMEOUT("200004", "设备指令发送超时"),
+
+    // ====================== 接口相关错误(30000~39999)======================
+    INTERFACE_CALL_FAIL("300000", "第三方接口调用失败"),
+    INTERFACE_PARAM_MISMATCH("300001", "接口参数不匹配"),
+    ILLEGAL_PARAM("300002", "非法参数"),
+    TOKEN_EXPIRED("300003", "令牌已过期"),
+    TOKEN_INVALID("300004", "令牌无效"),
+
+    // ====================== 数据存储错误(40000~49999)======================
+    DATA_SAVE_FAIL("400000", "数据保存失败"),
+    DATA_UPDATE_FAIL("400001", "数据更新失败"),
+    DATA_DELETE_FAIL("400002", "数据删除失败"),
+    DB_CONNECTION_ERROR("400003", "数据库连接异常"),
+
+    // ====================== 数据导出/导入错误(50000~59999)======================
+    DATA_IMPORT("500000", "数据导入失败"),
+    DATA_EXPORT("500001", "数据导出失败"),
+
+
+    // ====================== 交易订单(60000~69999)======================
+    TRADE_ORDER_NOT_FOUND("600000", "交易订单数据不存在"),
+    TRADE_ORDER_STATUS_ERROR("600001", "交易订单状态异常"),
+    TRADE_ORDER_NOT_ENT("600002", "交易订单无关联企业信息"),
+    TRADE_ORDER_AMOUNT_ERROR("70005", "交易订单的总运单量异常"),
+
+
+    // ====================== 物流订单(70000~79999)======================
+    LOGISTICS_ORDER_NOT_FOUND("700000", "物流订单数据不存在"),
+    LOGISTICS_ORDER_STATUS_ERROR("700001", "物流订单当前状态不可以接单"),
+    LOGISTICS_ORDER_NOT_GOODS("700002", "物流订单无商品信息"),
+    LOGISTICS_ORDER_NOT_ENT("700003", "物流订单无关联企业信息"),
+    LOGISTICS_ORDER_NOT_ADDRESS("700004", "物流订单无装卸货信息"),
+    LOGISTICS_ORDER_AMOUNT_ERROR("70005", "物流运单的总运单量异常"),
+
+    // ====================== 运单订单(80000~89999)======================
+    WAYBILL_ORDER_NOT_FOUND("80000", " 当前物流运单不存在"),
+    WAYBILL_ORDER_NOT_UNFINISHED("80001", " 当前车辆有未完成的状态"),
+    WAYBILL_ORDER_SUB_NOT_FOUND("80002", " 当前物流子运单不存在"),
+    WAYBILL_ORDER_ADDRESS_NOT_FOUND("80003", " 当前物流运单地址不存在"),
+    WAYBILL_ORDER_NOT_LOG_ORDER("80004", " 物流运单无关联物流订单数据"),
+    WAYBILL_ORDER_STATUS_ERROR("80005", " 物流运单状态异常"),
+    WAYBILL_ORDER_TICKET_NOT_FOUND("80005", " 当前物流运单装卸货信息不存在"),
+
+
+
+    // ====================== 司机/车辆(90000~99999)======================
+    DRIVER_NOT_FOUND("600000", "司机信息不存在"),
+    DRIVER_STATUS_ERROR("600001", "司机信息状态异常"),
+    TRUCK_NOT_FOUND("600002", "车辆信息不存在"),
+    TRUCK_STATUS_ERROR("600003", "车辆信息状态异常"),
+
+
+
+
+
+
+    ;
+
+
+    /** 错误编码 */
+    private final String code;
+
+    /** 错误描述 */
+    private final String desc;
+
+
+    // 构造方法(枚举的构造方法默认私有)
+    ErrorCodeEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+
+    // Getter 方法(供外部获取 code 和 desc)
+    public String getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+}

+ 48 - 0
sckw-common/sckw-common-core/src/main/java/com/sckw/core/exception/BusinessPlatfromException.java

@@ -0,0 +1,48 @@
+package com.sckw.core.exception;
+
+
+
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import lombok.Data;
+
+/**
+ * @Author: donglang
+ * @CreateTime: 2025-10-09
+ * @Description: 异常
+ * @Version: 1.0
+ */
+
+@Data
+public class BusinessPlatfromException extends RuntimeException {
+
+    /** 编码 */
+    private String errorCode;
+
+
+    /** 描述 */
+    private String errorMsg;
+
+
+    /**
+     * 构造函数
+     * @param errorCodeEnum 错误码
+     * @param errorMsg 具体错误信息
+     */
+    public BusinessPlatfromException(ErrorCodeEnum errorCodeEnum, String errorMsg) {
+        super(errorMsg = errorMsg == null ? errorCodeEnum.getDesc() : errorMsg);
+        this.errorCode = errorCodeEnum.getCode();
+        this.errorMsg = errorMsg;
+    }
+
+    /**
+     * 构造函数
+     * @param errorCodeEnum 错误码
+     * @param errorMsg 具体错误信息
+     * @param cause 异常
+     */
+    public BusinessPlatfromException(ErrorCodeEnum errorCodeEnum, String errorMsg, Throwable cause) {
+        super(errorMsg = errorMsg == null ? errorCodeEnum.getDesc() : errorMsg, cause);
+        this.errorCode = errorCodeEnum.getCode();
+        this.errorMsg = errorMsg;
+    }
+}

+ 0 - 3
sckw-common/sckw-common-core/src/main/java/com/sckw/core/web/constant/HttpStatus.java

@@ -255,7 +255,4 @@ public class HttpStatus {
     public static final String ENT_FAILED = "新增子企业,父级企业不能为空!";
 
 
-    public static final String LOG_ORDER_TAKING = "当前物流订单不是可接单状态!";
-
-
 }

+ 4 - 0
sckw-modules-api/sckw-fleet-api/src/main/java/com/sckw/fleet/api/RemoteFleetService.java

@@ -109,4 +109,8 @@ public interface RemoteFleetService {
     List<RTruckVo> findTruckByTruckIds(List<Long> truckIds);
 
     List<RFleetVo> findFleetByIds(Set<Long> fleetIds);
+
+    RTruckVo findTruckByTruckNo(String truckNo);
+
+    void updateTruckTareAmount(RTruckVo truckNo);
 }

+ 7 - 0
sckw-modules-api/sckw-fleet-api/src/main/java/com/sckw/fleet/api/model/vo/RDriverVo.java

@@ -56,4 +56,11 @@ public class RDriverVo implements Serializable {
      * 车辆业务状态
      */
     private Integer businessStatus;
+
+    /**
+     * 状态((0正常、1锁定)
+     */
+    private Integer status;
+
+
 }

+ 11 - 1
sckw-modules-api/sckw-fleet-api/src/main/java/com/sckw/fleet/api/model/vo/RTruckVo.java

@@ -30,7 +30,17 @@ public class RTruckVo implements Serializable {
     /**
      * 核定载质量/吨
      */
-    private Double actualWeight;
+    private BigDecimal actualWeight;
+
+    /**
+     * 车辆总质量(毛重)
+     */
+    private BigDecimal grossWeight;
+
+    /**
+     * 皮重
+     */
+    private BigDecimal tareWeight;
 
     /**
      * 挂车号

+ 10 - 0
sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/dubbo/TradeOrderInfoService.java

@@ -90,6 +90,16 @@ public interface TradeOrderInfoService {
      */
     HttpResult updateActualAmount(UpdateActualAmountParam param);
 
+    /**
+     * @desc: 更新物流订单
+     * @author: yzc
+     * @date: 2023-09-19 15:20
+     * @Param param:
+     * @return: com.sckw.core.web.response.HttpResult
+     */
+    HttpResult updateOrderActualAmount(UpdateActualAmountParam param);
+
+
     /**
      * @desc: 合同签约完成
      * @author: yzc

+ 11 - 0
sckw-modules-api/sckw-order-api/src/main/java/com/sckw/order/api/model/OrderDetailVo.java

@@ -29,6 +29,11 @@ public class OrderDetailVo implements Serializable {
     private static final long serialVersionUID = -2951319997472302360L;
     private Long entId;
 
+    /**
+     * 贸易订单id
+     */
+    private Long id;
+
     /**
      * 订单编号
      */
@@ -103,6 +108,12 @@ public class OrderDetailVo implements Serializable {
      * 托运方式
      */
     private Integer consignmentWay;
+
+    /**
+     * 交易订单状态
+     */
+    private Integer status;
+
     /**
      * 商品信息
      */

+ 23 - 2
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/dubbo/RemoteFleetServiceImpl.java

@@ -145,7 +145,7 @@ public class RemoteFleetServiceImpl implements RemoteFleetService {
             RTruckVo truckVo = new RTruckVo();
             truckVo.setId(truck.getId());
             truckVo.setTruckNo(truck.getTruckNo());
-            truckVo.setActualWeight(truck.getActualWeight() != null ? truck.getActualWeight().doubleValue() : null );
+            truckVo.setActualWeight(truck.getActualWeight());
             truckVo.setTrailerNo(truck.getTrailerNo());
             truckVo.setTotalComplete(truck.getTotalComplete());
             truckVo.setTotalTake(truck.getTotalTake());
@@ -327,7 +327,9 @@ public class RemoteFleetServiceImpl implements RemoteFleetService {
         RTruckVo rTruckVo = new RTruckVo();
         rTruckVo.setId(truck.getId());
         rTruckVo.setTruckNo(truck.getTruckNo());
-        rTruckVo.setActualWeight(Objects.isNull(truck.getActualWeight()) ? null : truck.getActualWeight().doubleValue());
+        rTruckVo.setActualWeight(truck.getActualWeight());
+        rTruckVo.setGrossWeight(truck.getGrossWeight());
+        rTruckVo.setTareWeight(truck.getTareWeight());
         rTruckVo.setTrailerNo(truck.getTrailerNo());
         rTruckVo.setTotalComplete(truck.getTotalComplete());
         rTruckVo.setTotalTake(truck.getTotalTake());
@@ -433,5 +435,24 @@ public class RemoteFleetServiceImpl implements RemoteFleetService {
         return rFleetVo;
     }
 
+    @Override
+    public RTruckVo findTruckByTruckNo(String truckNo) {
+        KwfTruck truck = kwfTruckRepository.findTruckByTruckNo(truckNo);
+        if (truck == null) {
+            return new RTruckVo();
+        }
+        return getTruckVo(truck);
+    }
+
+    @Override
+    public  void updateTruckTareAmount(RTruckVo truckNo) {
+        KwfTruck truck = kwfTruckRepository.findTruckByTruckNo(truckNo.getTruckNo());
+        if (truck == null) {
+            return;
+        }
+        truck.setTareWeight(truckNo.getTareWeight());
+        kwfTruckRepository.save(truck);
+    }
+
 
 }

+ 6 - 0
sckw-modules/sckw-fleet/src/main/java/com/sckw/fleet/repository/KwfTruckRepository.java

@@ -104,4 +104,10 @@ public class KwfTruckRepository extends ServiceImpl<KwfTruckMapper, KwfTruck> {
     public Boolean updateTruck(KwfTruck updateTruck) {
        return update(updateTruck, Wrappers.<KwfTruck>lambdaQuery().eq(KwfTruck::getId, updateTruck.getId()));
     }
+
+    public KwfTruck findTruckByTruckNo(String truckNo) {
+        return getOne(Wrappers.<KwfTruck>lambdaQuery()
+                .eq(BaseModel::getDelFlag,0)
+                .eq(KwfTruck::getTruckNo, truckNo));
+    }
 }

+ 20 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/dubbo/TradeOrderInfoServiceImpl.java

@@ -370,6 +370,24 @@ public class TradeOrderInfoServiceImpl implements TradeOrderInfoService {
         return HttpResult.ok();
     }
 
+    @Override
+    public HttpResult updateOrderActualAmount(UpdateActualAmountParam param) {
+        Long id = param.getTOrderId();
+        BigDecimal actualLoadAmount = param.getActualLoadAmount();
+        if (Objects.isNull(actualLoadAmount)) {
+            return HttpResult.error("装货总量不能为空!");
+        }
+
+        KwoTradeOrder order = kwoTradeOrderService.getById(id);
+        if (Objects.isNull(order)) {
+            return HttpResult.error("订单不存在!");
+        }
+        order.setActualAmount(actualLoadAmount);
+        kwoTradeOrderService.updateById(order);
+            
+        return HttpResult.ok();
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void contractSignCompleted(ContractSignCompletedParam param) {
@@ -474,6 +492,7 @@ public class TradeOrderInfoServiceImpl implements TradeOrderInfoService {
         KwoTradeOrderContract kwoTradeOrderContract = kwoTradeOrderContractRepository.queryByTradeOrderId(tradeOrderId);
 
         OrderDetailVo orderDetailRes = new OrderDetailVo();
+        orderDetailRes.setId(kwoTradeOrder.getId());
         orderDetailRes.setEntId(kwoTradeOrder.getEntId());
         orderDetailRes.setTOrderNo(kwoTradeOrder.getTOrderNo());
         orderDetailRes.setAmount(kwoTradeOrder.getAmount());
@@ -490,6 +509,7 @@ public class TradeOrderInfoServiceImpl implements TradeOrderInfoService {
         orderDetailRes.setSource(kwoTradeOrder.getSource());
         orderDetailRes.setChargeType(kwoTradeOrder.getChargeType());
         orderDetailRes.setConsignmentWay(kwoTradeOrder.getConsignmentWay());
+        orderDetailRes.setStatus(kwoTradeOrder.getStatus());
 
         if (Objects.nonNull(kwoTradeOrderGoods)){
             OrderDetailVo.GoodsInfo goodsInfo = new OrderDetailVo.GoodsInfo();

+ 5 - 0
sckw-modules/sckw-order/src/main/java/com/sckw/order/model/KwoTradeOrder.java

@@ -38,6 +38,11 @@ public class KwoTradeOrder extends BaseModel implements Serializable {
     @Serial
     private static final long serialVersionUID = -4156986025493740589L;
 
+    /**
+     * 订单id
+     */
+    private Long id;
+
     private Long entId;
 
     /**

+ 3 - 1
sckw-modules/sckw-order/src/main/java/com/sckw/order/repository/KwoTradeOrderRepository.java

@@ -39,6 +39,8 @@ public class KwoTradeOrderRepository extends ServiceImpl<KwoTradeOrderMapper, Kw
     }
 
     public KwoTradeOrder queryByTradeOrderId(Long tradeOrderId) {
-        return null;
+        return getOne(Wrappers.<KwoTradeOrder>lambdaQuery()
+                .eq(KwoTradeOrder::getId, tradeOrderId)
+                .eq(KwoTradeOrder::getDelFlag, 0));
     }
 }

+ 4 - 0
sckw-modules/sckw-transport/pom.xml

@@ -148,6 +148,10 @@
             <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
             <version>4.5.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+        </dependency>
 
     </dependencies>
 

+ 79 - 6
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/controller/enterpriseApp/AppWayBillController.java

@@ -6,13 +6,12 @@ import com.sckw.core.web.response.BaseResult;
 import com.sckw.core.web.response.HttpResult;
 import com.sckw.core.web.response.result.PageDataResult;
 import com.sckw.transport.model.dto.WaybillListAppDTO;
-import com.sckw.transport.model.param.LogisticsOrderResp;
-import com.sckw.transport.model.param.OrderCirculateQueryParam;
-import com.sckw.transport.model.param.OrderCirculateTotalTakeParam;
+import com.sckw.transport.model.param.*;
 import com.sckw.transport.model.vo.OrderCirculateTotalTakeVo;
 import com.sckw.transport.service.KwtLogisticsConsignmentService;
 import com.sckw.transport.service.KwtWaybillManagementService;
 import com.sckw.transport.service.KwtWaybillManagementV1Service;
+import com.sckw.transport.service.app.WaybillOrderService;
 import jakarta.validation.Valid;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -35,6 +34,8 @@ public class AppWayBillController {
     KwtWaybillManagementV1Service waybillManagementV1Service;
     @Autowired
     KwtLogisticsConsignmentService logisticsConsignmentService;
+    @Autowired
+    WaybillOrderService waybillOrderService;
 
     /**
      * APP 运单统计分类 - [运输中|已完成] - 数据库
@@ -222,12 +223,84 @@ public class AppWayBillController {
     /**
      * 物流订单接单
      *
-     * @param LogOrderId
+     * @param param
      * @return
      */
     @GetMapping("/orderTaking")
-    public BaseResult orderTaking(@RequestParam Long LogOrderId){
-       logisticsConsignmentService.orderTaking(LogOrderId);
+    public BaseResult orderTaking(@RequestBody @Valid OrderCirculateTakingQueryParam param){
+        waybillOrderService.orderTaking(param);
+        return BaseResult.success();
+    }
+
+    /**
+     * 取消订单接单
+     *
+     * @param param
+     * @return
+     */
+    @GetMapping("/cancelWaybillOrder")
+    public BaseResult cancelWaybillOrder(@RequestBody @Valid WaybillOrderCancelParam param){
+        waybillOrderService.cancelWaybillOrder(param);
+        return BaseResult.success();
+    }
+
+    /**
+     * 到达装货地点-手动推推送数据
+     *
+     * @param param
+     * @return
+     */
+    @GetMapping("/comeInto")
+    public BaseResult comeInto(@RequestBody @Valid WaybillOrderCmeIntoWeighParam param){
+        waybillOrderService.comeInto(param);
+        return BaseResult.success();
+    }
+
+    /**
+     * 已装货 -手动推推送数据
+     *
+     * @param param
+     * @return
+     */
+    @GetMapping("/loading")
+    public BaseResult loading(@RequestBody @Valid WaybillOrderLoadingParam param){
+        waybillOrderService.loading(param);
+        return BaseResult.success();
+    }
+
+    /**
+     * 离场过磅(计算毛重和净重)-手动推推送数据
+     *
+     * @param param
+     * @return
+     */
+    @GetMapping("/leave")
+    public BaseResult leave(@RequestBody @Valid WaybillOrderLeaveMockParam param){
+        waybillOrderService.leave(param);
+        return BaseResult.success();
+    }
+
+    /**
+     * 离场
+     *
+     * @param param
+     * @return
+     */
+    @GetMapping("/leavedWaybillOrder")
+    public BaseResult leavedWaybillOrder(@RequestBody @Valid WaybillOrderLeaveParam param){
+        waybillOrderService.leavedWaybillOrder(param);
+        return BaseResult.success();
+    }
+
+    /**
+     * 卸货
+     *
+     * @param param
+     * @return
+     */
+    @GetMapping("/unloadingWaybillOrder")
+    public BaseResult unloadingWaybillOrder(@RequestBody @Valid WaybillOrderUnloadParam param){
+        waybillOrderService.unloadingWaybillOrder(param);
         return BaseResult.success();
     }
 

+ 16 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/dao/KwtWaybillOrderNodeMapper.java

@@ -0,0 +1,16 @@
+package com.sckw.transport.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.sckw.transport.model.KwtWaybillOrderNode;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @author zk
+ * @desc 车辆运单-节点轨迹
+ * @date 2023/10/16
+ */
+@Mapper
+public interface KwtWaybillOrderNodeMapper extends BaseMapper<KwtWaybillOrderNode> {
+
+
+}

+ 166 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/AbstractWaybillOrderHandler.java

@@ -0,0 +1,166 @@
+package com.sckw.transport.handler;
+
+
+import com.alibaba.fastjson.JSON;
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import com.sckw.core.exception.BusinessPlatfromException;
+import com.sckw.fleet.api.RemoteFleetService;
+import com.sckw.order.api.dubbo.TradeOrderInfoService;
+import com.sckw.transport.model.KwtWaybillOrder;
+import com.sckw.transport.model.KwtWaybillOrderNode;
+import com.sckw.transport.model.KwtWaybillOrderSubtask;
+import com.sckw.transport.model.param.OrderCirculateTakingQueryParam;
+import com.sckw.transport.model.param.WaybillOrderLeaveMockParam;
+import com.sckw.transport.model.param.WaybillOrderProcessParam;
+import com.sckw.transport.repository.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Author: donglang
+ * Time: 2025-11-19
+ * Des: 运单操作处理器
+ * Version: 1.0
+ */
+
+@Slf4j
+public abstract class AbstractWaybillOrderHandler<T extends WaybillOrderProcessParam> {
+
+    // 依赖的Repository等组件
+    @Autowired
+    protected KwtWaybillOrderRepository waybillOrderRepository;
+    @Autowired
+    protected KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
+    @Autowired
+    protected KwtWaybillOrderNodeRepository waybillOrderNodeRepository;
+    @Autowired
+    protected KwtWaybillOrderTicketRepository waybillOrderTicketRepository;
+    @Autowired
+    protected KwtLogisticsOrderRepository logisticsOrderRepository;
+    @Autowired
+    protected KwtWaybillOrderAddressRepository waybillOrderAddressRepository;
+    @Autowired
+    protected KwtLogisticsOrderAddressRepository logisticsOrderAddressRepository;
+
+    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
+    protected RemoteFleetService remoteFleetService;
+
+    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 80000)
+    protected TradeOrderInfoService tradeOrderInfoService;
+
+
+
+    /**
+     * 模板方法 - 定义处理流程
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void handler(T param) {
+        try {
+            log.info("开始处理{},参数:{}", getProcessName(), JSON.toJSONString(param));
+
+            // 1. 参数校验
+            validate(param);
+            // 2. 获取运单(接单时返回null)
+            KwtWaybillOrder waybillOrder = getWaybillOrder(param);
+            // 3. 状态校验
+            checkState(param, waybillOrder);
+            // 4. 核心业务
+            doBusiness(param, waybillOrder);
+            // 5. 更新状态
+            updateStatus(param, waybillOrder);
+            // 6. 生成节点轨迹
+            createNodeTrace(param, waybillOrder);
+            // 7. 后置处理
+            afterProcess(param, waybillOrder);
+
+            log.info("{}处理完成", getProcessName());
+        } finally {
+            // 确保清理线程上下文,防止内存泄漏
+            BusinessContext.clear();
+        }
+
+    }
+
+    // 1. 参数校验
+    protected void validate(T param) {
+        if (param == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "参数不能为空");
+        }
+        // 非接单流程必须校验运单ID
+        if (!(param instanceof OrderCirculateTakingQueryParam) && param.getWaybillOrderId() == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "运单ID不能为空");
+        }
+    }
+
+    // 2. 获取运单
+    protected abstract KwtWaybillOrder getWaybillOrder(T param);
+
+    // 3. 状态校验
+    protected abstract void checkState(T param, KwtWaybillOrder waybillOrder);
+
+    // 4. 核心业务
+    protected abstract void doBusiness(T param, KwtWaybillOrder waybillOrder);
+
+    // 5. 更新状态
+    protected abstract void updateStatus(T param, KwtWaybillOrder waybillOrder);
+
+    // 6. 生成节点轨迹
+    private void createNodeTrace(T param, KwtWaybillOrder waybillOrder) {
+        if (waybillOrder == null) {
+            return;
+        }
+        // 非接单流程必须校验运单ID
+        if (param instanceof WaybillOrderLeaveMockParam) {
+            log.info("离场过磅(mock推送)不需要创建节点数据:{}", param.getWaybillOrderId());
+           return;
+        }
+
+        log.info("创建车辆运单-节点轨迹入参参数:{}", JSON.toJSONString(param));
+        KwtWaybillOrderSubtask subtask = getWaybillSubtask(waybillOrder.getId());
+        KwtWaybillOrderNode node = new KwtWaybillOrderNode();
+        node.setWOrderId(waybillOrder.getId());
+        node.setWSubtaskId(subtask.getId());
+        node.setOrderStatus(waybillOrder.getStatus());
+        node.setTruckId(waybillOrder.getTruckId());
+        node.setTruckNo(waybillOrder.getTruckNo());
+        node.setDriverId(waybillOrder.getDriverId());
+        node.setDriverName(waybillOrder.getDriverName());
+        node.setLng(param.getLng());
+        node.setLat(param.getLat());
+        waybillOrderNodeRepository.save(node);
+        log.info("记录{}节点轨迹成功,节点ID:{}", getProcessName(), node.getId());
+    }
+
+
+    protected abstract String getProcessName();
+
+    /**
+     * 查询运单
+     */
+    protected KwtWaybillOrder getWaybillOrder(Long waybillOrderId) {
+        KwtWaybillOrder waybillOrder = waybillOrderRepository.queryByBillOrderId(waybillOrderId);
+        if (waybillOrder == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_FOUND, "物流运单不存在!");
+        }
+        return waybillOrder;
+    }
+
+    /**
+     * 查询子运单
+     */
+    protected KwtWaybillOrderSubtask getWaybillSubtask(Long waybillOrderId) {
+        KwtWaybillOrderSubtask subtask = waybillOrderSubtaskRepository.queryByWOrderId(waybillOrderId);
+        if (subtask == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_SUB_NOT_FOUND, "未找到关联的子运单!");
+        }
+        return subtask;
+    }
+
+    // 7. 后置处理(子类可选实现)
+    protected void afterProcess(T param, KwtWaybillOrder waybillOrder) {}
+
+
+}
+

+ 78 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/BusinessContext.java

@@ -0,0 +1,78 @@
+package com.sckw.transport.handler;
+
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Author: donglang
+ * Time: 2025-11-19
+ * Des: 运单业务上下文:存储流程中所有需要的参数、中间数据和依赖组件
+ * Version: 1.0
+ */
+
+@Data
+@Accessors(chain = true)
+public class BusinessContext  {
+
+    private static final ThreadLocal<Map<String, Object>> CONTEXT = ThreadLocal.withInitial(HashMap::new);
+
+    /**
+     * 设置上下文值
+     */
+    public static void set(String key, Object value) {
+        CONTEXT.get().put(key, value);
+    }
+
+    /**
+     * 获取上下文值
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T get(String key) {
+        return (T) CONTEXT.get().get(key);
+    }
+
+    /**
+     * 获取上下文值,如果不存在则返回默认值
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T get(String key, T defaultValue) {
+        T value = (T) CONTEXT.get().get(key);
+        return value != null ? value : defaultValue;
+    }
+
+    /**
+     * 移除指定键的值
+     */
+    public static void remove(String key) {
+        CONTEXT.get().remove(key);
+    }
+
+    /**
+     * 清空当前线程的上下文
+     * 重要:必须在业务处理完成后调用,防止内存泄漏
+     */
+    public static void clear() {
+        CONTEXT.get().clear();
+        CONTEXT.remove();
+    }
+
+    /**
+     * 检查是否包含指定键
+     */
+    public static boolean contains(String key) {
+        return CONTEXT.get().containsKey(key);
+    }
+
+    /**
+     * 获取整个上下文Map(只读)
+     */
+    public static Map<String, Object> getAll() {
+        return new HashMap<>(CONTEXT.get());
+    }
+
+
+}

+ 118 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/CancelHandler.java

@@ -0,0 +1,118 @@
+package com.sckw.transport.handler;
+
+
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import com.sckw.core.exception.BusinessPlatfromException;
+import com.sckw.core.model.enums.CarWaybillV1Enum;
+import com.sckw.order.api.model.OrderDetailVo;
+import com.sckw.order.api.model.UpdateActualAmountParam;
+import com.sckw.transport.model.KwtLogisticsOrder;
+import com.sckw.transport.model.KwtWaybillOrder;
+import com.sckw.transport.model.KwtWaybillOrderSubtask;
+import com.sckw.transport.model.param.WaybillOrderCancelParam;
+import com.sckw.transport.repository.KwtLogisticsOrderRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.Objects;
+
+/**
+ * Author: donglang
+ * Time: 2025-11-19
+ * Des: 卸货
+ * Version: 1.0
+ */
+
+@Slf4j
+@Service
+public class CancelHandler extends AbstractWaybillOrderHandler<WaybillOrderCancelParam>{
+
+    @Autowired
+    private KwtLogisticsOrderRepository logisticsOrderRepository;
+
+    @Override
+    protected KwtWaybillOrder getWaybillOrder(WaybillOrderCancelParam param) {
+        return getWaybillOrder(param.getWaybillOrderId());
+    }
+
+    @Override
+    protected void checkState(WaybillOrderCancelParam param, KwtWaybillOrder waybill) {
+        if (!Objects.equals(CarWaybillV1Enum.PENDING_VEHICLE.getCode(), waybill.getStatus())) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "运单状态非待接单");
+        }
+    }
+
+    @Override
+    protected void doBusiness(WaybillOrderCancelParam param, KwtWaybillOrder waybill) {
+        //1.获取子运单任务量
+        KwtWaybillOrderSubtask subtask = getWaybillSubtask(waybill.getId());
+        BigDecimal entrustAmount = subtask.getEntrustAmount();
+
+        //2.更新上游订单:更新物流订单运输量
+        KwtLogisticsOrder logOrder = updateLogOrder(param, entrustAmount);
+
+        //3.更新上游订单:更新贸易订单运输量
+        updateTradeOrder(logOrder, entrustAmount);
+    }
+
+
+
+    /**
+     * 更新上游物流订单 - 减运输量
+     * @param param
+     * @param entrustAmount
+     * @return
+     */
+    private KwtLogisticsOrder updateLogOrder(WaybillOrderCancelParam param, BigDecimal entrustAmount) {
+        KwtLogisticsOrder logOrder = logisticsOrderRepository.queryByLogisticsOrderId(param.getLogOrderId());
+        if (logOrder == null) {
+            log.info("当前物流运单无关联物流订单数据:{}", param.getLogOrderId());
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_LOG_ORDER, "当前物流运单无关联物流订单数据!");
+        }
+
+        //取消接单的物流订单的总运输量不能为空
+        if (logOrder.getEntrustAmount() == null || logOrder.getEntrustAmount().compareTo(BigDecimal.ZERO) <= 0) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_AMOUNT_ERROR, "已接单物订单的总运单量不能为空或0!");
+        }
+        logOrder.setEntrustAmount(logOrder.getEntrustAmount().subtract(entrustAmount));
+        logisticsOrderRepository.updateById(logOrder);
+        log.info("更新上游物流订单运输量成功, 物流订单ID:{}", logOrder.getId());
+        return logOrder;
+    }
+
+
+    /**
+     * 更新上游贸易订单 - 减运输量
+     * @param logOrder
+     * @param entrustAmount
+     */
+    private void updateTradeOrder(KwtLogisticsOrder logOrder, BigDecimal entrustAmount) {
+        OrderDetailVo tradeOrder = tradeOrderInfoService.queryByTradeOrderId(logOrder.getTOrderId());
+        //取消接单的物流订单的总运输量不能为空
+        if (tradeOrder.getActualAmount() == null || tradeOrder.getActualAmount().compareTo(BigDecimal.ZERO) <= 0) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.TRADE_ORDER_AMOUNT_ERROR, "已接单交易订单的总运输量不能为空或0!");
+        }
+
+        UpdateActualAmountParam tradeParam = new UpdateActualAmountParam();
+        tradeParam.setTOrderId(tradeOrder.getId());
+        tradeParam.setActualLoadAmount(tradeOrder.getActualAmount().subtract(entrustAmount));
+        tradeOrderInfoService.updateOrderActualAmount(tradeParam);
+        log.info("更新上游贸易订单运输量成功, 贸易订单ID:{}", tradeOrder.getId());
+    }
+
+    @Override
+    protected void updateStatus(WaybillOrderCancelParam param, KwtWaybillOrder waybill) {
+        // 已取消状态
+        waybill.setStatus(CarWaybillV1Enum.APPROVAL_TREAT.getCode());
+        waybillOrderRepository.updateById(waybill);
+    }
+
+    @Override
+    protected String getProcessName() {
+        return "取消接单";
+    }
+
+
+}

+ 83 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/ComeIntoHandler.java

@@ -0,0 +1,83 @@
+package com.sckw.transport.handler;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import com.sckw.core.exception.BusinessPlatfromException;
+import com.sckw.core.model.enums.AddressTypeEnum;
+import com.sckw.core.model.enums.CarWaybillV1Enum;
+import com.sckw.fleet.api.RemoteFleetService;
+import com.sckw.fleet.api.model.vo.RTruckVo;
+import com.sckw.transport.model.KwtWaybillOrder;
+import com.sckw.transport.model.KwtWaybillOrderTicket;
+import com.sckw.transport.model.param.WaybillOrderCmeIntoWeighParam;
+import com.sckw.transport.repository.KwtWaybillOrderTicketRepository;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Objects;
+
+/**
+ * Author: donglang
+ * Time: 2025-11-19
+ * Des: 到达装货地点Handler
+ * Version: 1.0
+ */
+
+@Service
+public class ComeIntoHandler extends AbstractWaybillOrderHandler<WaybillOrderCmeIntoWeighParam>{
+
+    @Autowired
+    private KwtWaybillOrderTicketRepository waybillOrderTicketRepository;
+
+
+    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
+    protected RemoteFleetService remoteFleetService;
+
+    @Override
+    protected KwtWaybillOrder getWaybillOrder(WaybillOrderCmeIntoWeighParam param) {
+        return getWaybillOrder(param.getWaybillOrderId());
+    }
+
+    @Override
+    protected void checkState(WaybillOrderCmeIntoWeighParam param, KwtWaybillOrder waybillOrder) {
+        if (!Objects.equals(CarWaybillV1Enum.PENDING_VEHICLE.getCode(), waybillOrder.getStatus())) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "当前物流运单状态不正确,无法推进下一节点");
+        }
+    }
+
+    @Override
+    protected void doBusiness(WaybillOrderCmeIntoWeighParam param, KwtWaybillOrder waybillOrder) {
+        //1.填充运单皮重
+        LambdaQueryWrapper<KwtWaybillOrderTicket>  queryWrapper = Wrappers.<KwtWaybillOrderTicket>lambdaQuery()
+                .eq(KwtWaybillOrderTicket::getWOrderId, param.getWaybillOrderId())
+                .eq(KwtWaybillOrderTicket::getType, AddressTypeEnum.SHIPMENT.getCode());
+        KwtWaybillOrderTicket orderTicket = waybillOrderTicketRepository.getOne(queryWrapper);
+        orderTicket.setTareAmount(param.getTareAmount());
+        waybillOrderTicketRepository.save(orderTicket);
+
+        //2.填充首次皮重
+        RTruckVo truck = remoteFleetService.findTruckByTruckNo(param.getTruckNo());
+        if (truck != null && truck.getTareWeight() == null) {
+            RTruckVo truckNo = new RTruckVo();
+            truckNo.setId(truck.getId());
+            truckNo.setTareWeight(param.getTareAmount());
+            remoteFleetService.updateTruckTareAmount(truckNo);
+        }
+    }
+
+    @Override
+    protected void updateStatus(WaybillOrderCmeIntoWeighParam param, KwtWaybillOrder waybillOrder) {
+        // 到达装货地点状态
+        waybillOrder.setStatus(CarWaybillV1Enum.REFUSE_TRAFFIC.getCode());
+        waybillOrderRepository.updateById(waybillOrder);
+    }
+
+
+    @Override
+    protected String getProcessName() {
+        return "到达装货地点";
+    }
+}

+ 61 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/LeaveHandler.java

@@ -0,0 +1,61 @@
+package com.sckw.transport.handler;
+
+
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import com.sckw.core.exception.BusinessPlatfromException;
+import com.sckw.core.model.enums.CarWaybillV1Enum;
+import com.sckw.transport.model.KwtWaybillOrder;
+import com.sckw.transport.model.param.WaybillOrderLeaveParam;
+import com.sckw.transport.repository.KwtWaybillOrderSubtaskRepository;
+import com.sckw.transport.repository.KwtWaybillOrderTicketRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Objects;
+
+/**
+ * Author: donglang
+ * Time: 2025-11-19
+ * Des: 离场
+ * Version: 1.0
+ */
+
+@Slf4j
+@Service
+public class LeaveHandler extends AbstractWaybillOrderHandler<WaybillOrderLeaveParam> {
+
+    @Autowired
+    private KwtWaybillOrderTicketRepository waybillOrderTicketRepository;
+    @Autowired
+    private KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
+
+
+    @Override
+    protected KwtWaybillOrder getWaybillOrder(WaybillOrderLeaveParam param) {
+        return getWaybillOrder(param.getWaybillOrderId());
+    }
+
+    @Override
+    protected void checkState(WaybillOrderLeaveParam param, KwtWaybillOrder waybill) {
+        if (!Objects.equals(CarWaybillV1Enum.EXIT_COMPLETED.getCode(), waybill.getStatus())) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "运单状态不是已装货状态, 无法推进下一节点!");
+        }
+    }
+
+    @Override
+    protected void doBusiness(WaybillOrderLeaveParam param, KwtWaybillOrder waybill) {
+        // 离场无额外业务逻辑
+    }
+
+    @Override
+    protected void updateStatus(WaybillOrderLeaveParam param, KwtWaybillOrder waybill) {
+        waybill.setStatus(CarWaybillV1Enum.WAIT_LOADING.getCode()); // 已离场状态
+        waybillOrderRepository.updateById(waybill);
+    }
+
+    @Override
+    protected String getProcessName() {
+        return "离场";
+    }
+}

+ 115 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/LeaveMockHandler.java

@@ -0,0 +1,115 @@
+package com.sckw.transport.handler;
+
+
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import com.sckw.core.exception.BusinessPlatfromException;
+import com.sckw.core.model.enums.AddressTypeEnum;
+import com.sckw.core.model.enums.CarWaybillV1Enum;
+import com.sckw.transport.model.KwtWaybillOrder;
+import com.sckw.transport.model.KwtWaybillOrderSubtask;
+import com.sckw.transport.model.KwtWaybillOrderTicket;
+import com.sckw.transport.model.param.WaybillOrderLeaveMockParam;
+import com.sckw.transport.repository.KwtWaybillOrderSubtaskRepository;
+import com.sckw.transport.repository.KwtWaybillOrderTicketRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Author: donglang
+ * Time: 2025-11-19
+ * Des: 离场过磅(计算毛重和净重)
+ * Version: 1.0
+ */
+
+@Slf4j
+@Service
+public class LeaveMockHandler extends AbstractWaybillOrderHandler<WaybillOrderLeaveMockParam> {
+
+    @Autowired
+    private KwtWaybillOrderTicketRepository waybillOrderTicketRepository;
+    @Autowired
+    private KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
+
+
+    @Override
+    protected KwtWaybillOrder getWaybillOrder(WaybillOrderLeaveMockParam param) {
+        return getWaybillOrder(param.getWaybillOrderId());
+    }
+
+    @Override
+    protected void checkState(WaybillOrderLeaveMockParam param, KwtWaybillOrder waybillOrder) {
+        if (!Objects.equals(CarWaybillV1Enum.EXIT_COMPLETED.getCode(), waybillOrder.getStatus())) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "运单状态不符合离场过磅条件,无法推进下一节点!");
+        }
+    }
+
+    @Override
+    protected void doBusiness(WaybillOrderLeaveMockParam param, KwtWaybillOrder waybillOrder) {
+        List<KwtWaybillOrderTicket> ticketList = waybillOrderTicketRepository.queryByWOrderId(param.getWaybillOrderId());
+        // 按 type 分组
+        Map<Integer, KwtWaybillOrderTicket> ticketMap = ticketList.stream()
+                .collect(Collectors.toMap(KwtWaybillOrderTicket::getType, Function.identity(), (a, b) -> a));
+        //1.填充毛重
+        updateGrossAmount(param, ticketMap);
+        //2.填充装货净重
+        updateLoadAmount(param, waybillOrder, ticketMap);
+    }
+
+    /**
+     * 填充毛重
+     * @param param
+     * @param ticketMap
+     */
+    private void updateGrossAmount(WaybillOrderLeaveMockParam param, Map<Integer, KwtWaybillOrderTicket> ticketMap) {
+        //查询卸货信息,用于记录毛重
+        KwtWaybillOrderTicket takeTicket = ticketMap.getOrDefault(AddressTypeEnum.TAKE.getCode(), new KwtWaybillOrderTicket());
+        if (takeTicket == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_TICKET_NOT_FOUND, "当前物流运单装卸货信息不存在,无法记录毛重!");
+        }
+        takeTicket.setGrossAmount(param.getGrossAmount());
+        waybillOrderTicketRepository.updateById(takeTicket);
+    }
+
+    /**
+     * 填充装货净重
+     * @param param
+     * @param waybillOrder
+     * @param ticketMap
+     */
+    private void updateLoadAmount(WaybillOrderLeaveMockParam param, KwtWaybillOrder waybillOrder, Map<Integer, KwtWaybillOrderTicket> ticketMap) {
+        //查询卸货信息,用于获取皮重
+        KwtWaybillOrderTicket shipmentTicket  = ticketMap.getOrDefault(AddressTypeEnum.SHIPMENT.getCode(), new KwtWaybillOrderTicket());
+        if (shipmentTicket == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_TICKET_NOT_FOUND, "当前物流运单装卸货信息不存在,无法获取皮重!");
+        }
+        //皮重
+        BigDecimal tareAmount = shipmentTicket.getTareAmount();
+
+        //更新子运单的装货净重
+        KwtWaybillOrderSubtask subtask = waybillOrderSubtaskRepository.queryByWOrderId(waybillOrder.getId());
+        if (subtask == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_SUB_NOT_FOUND, "未找到关联的子运单!");
+        }
+        BigDecimal loadAmount = param.getGrossAmount().subtract(Optional.ofNullable(tareAmount).orElse(BigDecimal.ZERO));
+        subtask.setLoadAmount(loadAmount);
+        subtask.setLoadTime(new Date());
+        waybillOrderSubtaskRepository.updateById(subtask);
+        log.info("物流运单离场过磅成功!运单ID: {}, 毛重: {}, 皮重: {}, 装货净重: {}", param.getWaybillOrderId(), param.getGrossAmount(), tareAmount, loadAmount);
+    }
+
+    @Override
+    protected void updateStatus(WaybillOrderLeaveMockParam param, KwtWaybillOrder waybill) {
+        // 离场过磅不更新状态
+    }
+
+    @Override
+    protected String getProcessName() {
+        return "离场过磅(计算毛重和净重)";
+    }
+}

+ 51 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/LoadingHandler.java

@@ -0,0 +1,51 @@
+package com.sckw.transport.handler;
+
+
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import com.sckw.core.exception.BusinessPlatfromException;
+import com.sckw.core.model.enums.CarWaybillV1Enum;
+import com.sckw.transport.model.KwtWaybillOrder;
+import com.sckw.transport.model.param.WaybillOrderLoadingParam;
+import org.springframework.stereotype.Service;
+
+import java.util.Objects;
+
+/**
+ * Author: donglang
+ * Time: 2025-11-19
+ * Des: 已装货 -手动推推送数据
+ * Version: 1.0
+ */
+
+@Service
+public class LoadingHandler extends AbstractWaybillOrderHandler<WaybillOrderLoadingParam>{
+
+    @Override
+    protected KwtWaybillOrder getWaybillOrder(WaybillOrderLoadingParam param) {
+        return getWaybillOrder(param.getWaybillOrderId());
+    }
+
+    @Override
+    protected void checkState(WaybillOrderLoadingParam param, KwtWaybillOrder waybillOrder) {
+        if (!Objects.equals(CarWaybillV1Enum.REFUSE_TRAFFIC.getCode(), waybillOrder.getStatus())) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "运单状态非到达装货地点, 无法推进下一节点!");
+        }
+    }
+
+    @Override
+    protected void doBusiness(WaybillOrderLoadingParam param, KwtWaybillOrder waybillOrder) {
+        // 装货无额外业务逻辑
+    }
+
+    @Override
+    protected void updateStatus(WaybillOrderLoadingParam param, KwtWaybillOrder waybillOrder) {
+        // 已装货状态
+        waybillOrder.setStatus(CarWaybillV1Enum.EXIT_COMPLETED.getCode());
+        waybillOrderRepository.updateById(waybillOrder);
+    }
+
+    @Override
+    protected String getProcessName() {
+        return "已装货";
+    }
+}

+ 496 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/TakingOrderHandler.java

@@ -0,0 +1,496 @@
+package com.sckw.transport.handler;
+
+
+import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Lists;
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import com.sckw.core.exception.BusinessPlatfromException;
+import com.sckw.core.model.constant.Global;
+import com.sckw.core.model.enums.AddressTypeEnum;
+import com.sckw.core.model.enums.CarWaybillV1Enum;
+import com.sckw.core.model.enums.LogisticsOrderV1Enum;
+import com.sckw.core.utils.CollectionUtils;
+import com.sckw.fleet.api.model.vo.RDriverVo;
+import com.sckw.fleet.api.model.vo.RTruckVo;
+import com.sckw.order.api.model.OrderDetailVo;
+import com.sckw.order.api.model.UpdateActualAmountParam;
+import com.sckw.transport.model.*;
+import com.sckw.transport.model.param.OrderCirculateTakingQueryParam;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Author: donglang
+ * Time: 2025-11-19
+ * Des: 接单处理器Handler
+ * Version: 1.0
+ */
+
+@Slf4j
+@Service
+public class TakingOrderHandler extends AbstractWaybillOrderHandler<OrderCirculateTakingQueryParam> {
+
+    // 定义常量
+    private static final BigDecimal EIGHTY_PERCENT = new BigDecimal("0.8");
+    private static final BigDecimal TWO_TONS = new BigDecimal("2");
+    // 定义禁止运单接单的状态集合
+    private static final List<Integer> FORBIDDEN_STATUSES = Arrays.asList(
+            CarWaybillV1Enum.PENDING_VEHICLE.getCode(),
+            CarWaybillV1Enum.REFUSE_TRAFFIC.getCode(),
+            CarWaybillV1Enum.EXIT_COMPLETED.getCode(),
+            CarWaybillV1Enum.WAIT_LOADING.getCode(),
+            CarWaybillV1Enum.COMPLETION_UNLOADING.getCode()
+    );
+
+
+    @Override
+    protected KwtWaybillOrder getWaybillOrder(OrderCirculateTakingQueryParam param) {
+        // 接单时运单未创建
+        return null;
+    }
+
+
+    @Override
+    protected void checkState(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder) {
+        // 1.校验物流订单
+        KwtLogisticsOrder logOrder = checkLogOrder(param);
+        // 2.校验交易订单
+        OrderDetailVo tradeOrder = checkTradeOrder(param, logOrder);
+        // 3.校验司机
+        RDriverVo driver = checkDriver(param);
+        // 4.校验车辆
+        RTruckVo truck = checkTruck(param);
+        // 5.校验车辆是否已有未完成运单
+        checkTruckUnfinished(param);
+
+        // 存储到线程上下文
+        BusinessContext.set("logOrder", logOrder);
+        BusinessContext.set("tradeOrder", tradeOrder);
+        BusinessContext.set("driver", driver);
+        BusinessContext.set("truck", truck);
+    }
+
+
+    @Override
+    protected void doBusiness(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybill) {
+        KwtLogisticsOrder logOrder = BusinessContext.get("logOrder");
+        OrderDetailVo tradeOrder = BusinessContext.get("tradeOrder");
+        RDriverVo driver = BusinessContext.get("driver");
+        RTruckVo truck = BusinessContext.get("truck");
+
+        // 计算任务量(含接单校验)
+        BigDecimal truckLoadVolume = queryCurTruckLoadVolume(truck, tradeOrder);
+
+        //1、生成物流运单
+        KwtWaybillOrder waybillOrder = createWaybillOrder(param, driver, truck);
+
+        //2、生成物流子运单
+        KwtWaybillOrderSubtask waybillOrderSubtask = createWaybillOrderSubtask(param, waybillOrder, truckLoadVolume);
+
+        //3、生成物流运单地址
+        List<KwtWaybillOrderAddress> addresses = createWaybillOrderAddress(param, waybillOrder, waybillOrderSubtask);
+
+        //4、生成车辆运单-装卸货信息
+        createWaybillOrderTicket(param, logOrder, waybillOrder, waybillOrderSubtask, addresses, truck);
+
+        //5、更新上游订单:回写贸易订单
+        updateTradeOrder(tradeOrder, truckLoadVolume);
+
+        //6、更新上游订单:回写物流订单
+        updateLogOrder(logOrder, truckLoadVolume);
+
+        log.info("物流订单接单完成,运单ID:{}", waybillOrder.getId());
+    }
+
+
+
+
+
+    /**
+     * 校验物流订单是否是可接单状态
+     * @param param
+     * @return
+     */
+    private KwtLogisticsOrder checkLogOrder(OrderCirculateTakingQueryParam param) {
+        KwtLogisticsOrder logOrder = logisticsOrderRepository.queryByLogOrderIdAndStatus(param.getLogOrderId(), LogisticsOrderV1Enum.IN_TRANSIT.getCode());
+        if (logOrder == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_STATUS_ERROR, "物流订单非可接单状态");
+        }
+        return logOrder;
+    }
+
+    /**
+     * 校验交易订单状态
+     * @param param
+     * @param logOrder
+     * @return
+     */
+    private OrderDetailVo checkTradeOrder(OrderCirculateTakingQueryParam param, KwtLogisticsOrder logOrder) {
+        OrderDetailVo orderDetail = tradeOrderInfoService.queryByTradeOrderId(logOrder.getTOrderId());
+        if (orderDetail == null || orderDetail.getStatus() == Global.NUMERICAL_ONE) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.TRADE_ORDER_STATUS_ERROR, "当前物流订单的交易订单已锁定");
+        }
+        return orderDetail;
+    }
+
+    /**
+     * 校验司机状态
+     * @param param
+     * @return
+     */
+    private RDriverVo checkDriver(OrderCirculateTakingQueryParam param) {
+        RDriverVo driver = remoteFleetService.findDriver(param.getDriverId());
+        if (driver == null || driver.getStatus() == Global.NUMERICAL_ONE) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.DRIVER_STATUS_ERROR, "当前司机已锁定");
+        }
+        return driver;
+    }
+
+    /**
+     * 校验车辆状态
+     * @param param
+     * @return
+     */
+    private RTruckVo checkTruck(OrderCirculateTakingQueryParam param) {
+        RTruckVo truckNo = remoteFleetService.findTruckByTruckNo(param.getTruckNo());
+        if (truckNo == null || truckNo.getStatus() == Global.NUMERICAL_ONE) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.TRUCK_STATUS_ERROR, "当前车辆已锁定");
+        }
+        return truckNo;
+    }
+
+    /**
+     * 校验车辆是否已有未完成运单(不可继续接单状态:已接单、已入场、已装货、已离场、审核驳回)
+     * @param param
+     */
+    private void checkTruckUnfinished(OrderCirculateTakingQueryParam param) {
+        List<KwtWaybillOrder> wbOrderByTruckNo = waybillOrderRepository.findWbOrderByTruckNo(param.getTruckNo());
+        boolean hasForbidden  = wbOrderByTruckNo.stream()
+                .anyMatch(order -> order != null && FORBIDDEN_STATUSES.contains(order.getStatus()));
+        if (hasForbidden) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_UNFINISHED, "当前车辆有未完成的状态,不可继续接单");
+        }
+    }
+
+
+    /**
+     * 计算当前车辆任务量:
+     * 若有皮重:任务量 = 核定载重 - 皮重
+     * 若无皮重:任务量 = 核定载重 × 80%
+     * <p>
+     * 1.当订单余量>=车辆的(法定载重-首次皮重)且<(法定载重-首次皮重 + 2)时,接取的任务量为车辆的(法定载重-首次皮重);
+     * 2.订单余量<车辆的(法定载重-首次皮重)时,该车辆无法接单;
+     * 3.当订单余量>= (法定载重-首次皮重 + 2)时,接取的任务量为 (法定载重-首次皮重 + 2)
+     *
+     * @param truckNo
+     */
+    private BigDecimal queryCurTruckLoadVolume(RTruckVo truckNo, OrderDetailVo tradeOrder) {
+        //核定载重
+        BigDecimal actualWeight = truckNo.getActualWeight();
+        if (actualWeight == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.RESOURCE_NOT_FOUND, "车辆核定载重不能为空!");
+        }
+        log.info("车辆核定载重:{}", actualWeight);
+        //首次皮重
+        BigDecimal tareWeight = truckNo.getTareWeight();
+        //任务量
+        BigDecimal loadVolume;
+        if (tareWeight != null) {
+            // 有皮重:任务量 = 核定载重 - 皮重
+            loadVolume = actualWeight.subtract(tareWeight);
+            log.info("车辆有皮重,皮重:{}, 任务量:{}", tareWeight, loadVolume);
+
+        } else {
+            // 无皮重:任务量 = 核定载重 × 80%
+            loadVolume = actualWeight.multiply(EIGHTY_PERCENT);
+            log.info("车辆无皮重,按80%核定载重计算,车辆任务量:{}", loadVolume);
+        }
+
+        //订单分配总量
+        BigDecimal entrustAmount = tradeOrder.getEntrustAmount();
+        //订单实际交付量
+        BigDecimal actualAmount = tradeOrder.getActualAmount();
+        if (entrustAmount == null || actualAmount == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "订单分配总量或订单实际交付量不能为空!");
+        }
+        //订单余量 = 分配总量 - 实际交付量
+        BigDecimal remainingAmount = entrustAmount.subtract(actualAmount);
+        log.info("订单余量 = 分配总量:{} - 实际交付量:{} = 车辆任务量:{}", entrustAmount, actualAmount, remainingAmount);
+
+        // 最终接取的任务量
+        BigDecimal taskAmount;
+        BigDecimal loadVolumePlus2 = loadVolume.add(TWO_TONS);
+        if (remainingAmount.compareTo(loadVolume) < 0) {
+            // 规则2:订单余量 < 任务量 → 无法接单
+            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, String.format("订单余量不足,无法接单, 订单余量:%s, 车辆任务量:%s", remainingAmount, loadVolume));
+        } else if (remainingAmount.compareTo(loadVolumePlus2) >= 0) {
+            // 规则3:订单余量 >= 任务量+2 → 接取任务量+2
+            taskAmount = loadVolumePlus2;
+            log.info("订单余量充足,按(任务量+2吨)接单,最终任务量: {}", taskAmount);
+        } else {
+            // 规则1:订单余量 >= 任务量 且 < 任务量+2 → 接取任务量
+            taskAmount = loadVolume;
+            log.info("订单余量适中,按基础任务量接单,最终任务量: {}", taskAmount);
+        }
+        log.info("最终任务量:{}", remainingAmount);
+        return taskAmount;
+    }
+
+    /**
+     * 创建物流运单
+     *
+     * @param param
+     */
+    private KwtWaybillOrder createWaybillOrder(OrderCirculateTakingQueryParam param, RDriverVo driver, RTruckVo truckNo) {
+        log.info("创建物流运单入参参数:{}", JSON.toJSONString(param));
+        KwtWaybillOrder waybillOrder = new KwtWaybillOrder();
+        waybillOrder.setEntId(param.getEntId());
+        waybillOrder.setWOrderNo(null);
+        waybillOrder.setType(1);
+        waybillOrder.setTruckId(truckNo.getId());
+        waybillOrder.setTruckNo(param.getTruckNo());
+        waybillOrder.setDriverId(param.getDriverId());
+        waybillOrder.setDriverName(driver.getName());
+        waybillOrder.setDriverPhone(driver.getPhone());
+        waybillOrder.setDriverIdcard(driver.getIdcard());
+        waybillOrder.setStatus(CarWaybillV1Enum.PENDING_VEHICLE.getCode());
+        waybillOrder.setTaskStartTime(new Date());
+        waybillOrderRepository.save(waybillOrder);
+        log.info("创建物流运单成功,运单ID:{}", waybillOrder.getId());
+
+        return waybillOrder;
+
+    }
+
+    /**
+     * 创建物流子运单
+     *
+     * @param param
+     */
+    private KwtWaybillOrderSubtask createWaybillOrderSubtask(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder,
+                                                             BigDecimal truckLoadVolume) {
+        log.info("创建物流子运单入参参数:{}", JSON.toJSONString(param));
+        KwtWaybillOrderSubtask subtask = new KwtWaybillOrderSubtask();
+
+        subtask.setEntId(param.getEntId());
+        subtask.setLOrderId(param.getLogOrderId());
+        subtask.setWOrderId(waybillOrder.getId());
+        subtask.setWOrderNo(waybillOrder.getWOrderNo());
+        subtask.setUnit(null);
+
+        subtask.setEntrustAmount(truckLoadVolume);
+        subtask.setLoadTime(waybillOrder.getTaskStartTime());
+        subtask.setUnloadTime(waybillOrder.getEndTime());
+        subtask.setStatus(CarWaybillV1Enum.PENDING_VEHICLE.getCode());
+        waybillOrderSubtaskRepository.save(subtask);
+        log.info("创建物流子运单成功,子运单ID:{}", subtask.getId());
+
+        return subtask;
+
+    }
+
+    /**
+     * 创建物流运单地址
+     *
+     * @param param
+     */
+    private List<KwtWaybillOrderAddress> createWaybillOrderAddress(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder,
+                                                                   KwtWaybillOrderSubtask waybillOrderSubtask) {
+        log.info("创建物流运单地址入参参数,logOrderId:{}", param.getLogOrderId());
+        //地址
+        Map<String, KwtLogisticsOrderAddress> logOrderIdAndAddressMap = getKwtLogisticsOrderAddressMap(Lists.newArrayList(param.getLogOrderId()));
+        List<KwtWaybillOrderAddress> createdAddresses = new ArrayList<>();
+
+        //装货地址
+        KwtLogisticsOrderAddress shipmentSource = logOrderIdAndAddressMap.getOrDefault(
+                param.getLogOrderId() + "-" + AddressTypeEnum.SHIPMENT.getCode(), new KwtLogisticsOrderAddress());
+        KwtWaybillOrderAddress shipmentAddress = createAddress(waybillOrder, waybillOrderSubtask, shipmentSource, AddressTypeEnum.SHIPMENT);
+        createdAddresses.add(shipmentAddress);
+        log.info("创建物流运单装货地址成功,运单地址ID:{}", shipmentAddress.getId());
+
+        //卸货地址
+        KwtLogisticsOrderAddress takeSource = logOrderIdAndAddressMap.getOrDefault(
+                param.getLogOrderId() + "-" + AddressTypeEnum.TAKE.getCode(), new KwtLogisticsOrderAddress());
+        KwtWaybillOrderAddress takeAddress = createAddress(waybillOrder, waybillOrderSubtask, takeSource, AddressTypeEnum.TAKE);
+        createdAddresses.add(takeAddress);
+        log.info("创建物流运单卸货地址成功,运单地址ID:{}", takeAddress.getId());
+
+        log.info("成功创建{}个运单地址", createdAddresses.size());
+        return createdAddresses;
+    }
+
+    /**
+     * 保存运单物流地址
+     * @param waybillOrder
+     * @param subtask
+     * @param orderAddress
+     */
+    private KwtWaybillOrderAddress createAddress(KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask subtask,
+                                                 KwtLogisticsOrderAddress orderAddress, AddressTypeEnum typeEnum) {
+        KwtWaybillOrderAddress address = new KwtWaybillOrderAddress();
+        address.setWOrderId(waybillOrder.getId());
+        address.setWSubtaskId(subtask.getId());
+        address.setLAddressId(orderAddress.getId());
+        address.setAddressType(typeEnum.getCode());
+        address.setName(orderAddress.getName());
+        address.setType(orderAddress.getType());
+        address.setContacts(orderAddress.getContacts());
+        address.setPhone(orderAddress.getPhone());
+        address.setCityCode(orderAddress.getCityCode());
+        address.setCityName(orderAddress.getCityName());
+        address.setDetailAddress(orderAddress.getDetailAddress());
+        address.setLat(orderAddress.getLat());
+        address.setLng(orderAddress.getLng());
+        address.setFence(orderAddress.getFence());
+        address.setEntryType(orderAddress.getEntryType());
+        address.setPlanTime(waybillOrder.getTaskStartTime());
+        address.setSort(Global.NUMERICAL_ONE);
+        address.setEntrustAmount(subtask.getEntrustAmount());
+
+        waybillOrderAddressRepository.save(address);
+        return address;
+    }
+
+    /**
+     * 生成车辆运单-装卸货信息
+     *
+     * @param param
+     * @param waybillOrder
+     */
+    private void createWaybillOrderTicket(OrderCirculateTakingQueryParam param, KwtLogisticsOrder logOrder,
+                                          KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask waybillOrderSubtask,
+                                          List<KwtWaybillOrderAddress> waybillOrderAddresses, RTruckVo truckNo) {
+        log.info("创建车辆运单-装卸货信息入参参数:{}", JSON.toJSONString(param));
+
+        //装货地址
+        KwtWaybillOrderAddress shipmentAddress = getWaybillOrderAddress(waybillOrderAddresses, AddressTypeEnum.SHIPMENT);
+        createTicket(waybillOrder, waybillOrderSubtask, shipmentAddress, logOrder, truckNo);
+        log.info("创建车辆运单-装卸货信息成功!");
+
+        //卸货地址
+        KwtWaybillOrderAddress takeAddress = getWaybillOrderAddress(waybillOrderAddresses, AddressTypeEnum.TAKE);
+        createTicket(waybillOrder, waybillOrderSubtask, shipmentAddress, logOrder, truckNo);
+        log.info("创建车辆运单-装卸货信息成功!");
+
+    }
+
+    /**
+     * 运单地址(装货、卸货地址)
+     *
+     * @param waybillOrderAddresses
+     * @param typeEnum
+     * @return
+     */
+    private KwtWaybillOrderAddress getWaybillOrderAddress(List<KwtWaybillOrderAddress> waybillOrderAddresses, AddressTypeEnum typeEnum) {
+        return waybillOrderAddresses.stream()
+                .filter(address -> address != null && typeEnum.getCode() == address.getType())
+                .findFirst()
+                .orElseThrow(() -> new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_ADDRESS_NOT_FOUND, "未找到装货地址数据!"));
+    }
+
+    /**
+     * 保存车辆运单-装卸货信息
+     *
+     * @param waybillOrder
+     * @param waybillOrderSubtask
+     * @param shipmentAddress
+     */
+    private void createTicket(KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask waybillOrderSubtask,
+                              KwtWaybillOrderAddress shipmentAddress, KwtLogisticsOrder logOrder, RTruckVo truckNo) {
+        KwtWaybillOrderTicket ticket = new KwtWaybillOrderTicket();
+        ticket.setWOrderId(waybillOrder.getId());
+        ticket.setWSubtaskId(waybillOrderSubtask.getId());
+        ticket.setWAddressId(shipmentAddress.getId());
+        ticket.setType(shipmentAddress.getAddressType());
+        ticket.setUnit(logOrder.getUnit());
+        ticket.setAmount(BigDecimal.ZERO);
+        ticket.setGrossAmount(truckNo.getGrossWeight());
+        ticket.setTareAmount(truckNo.getTareWeight());
+        waybillOrderTicketRepository.save(ticket);
+    }
+
+    /**
+     * 回写贸易订单数据
+     * @param tradeOrder
+     */
+    private void updateTradeOrder(OrderDetailVo tradeOrder, BigDecimal truckLoadVolume) {
+        log.info("更新上游贸易订单运输量数据,tradeOrderId:{}", tradeOrder.getId());
+        // 计算当前车辆运输量
+        BigDecimal totalLoadVolume = Optional.ofNullable(tradeOrder.getActualAmount())
+                .map(entrust -> entrust.add(truckLoadVolume))
+                .orElse(truckLoadVolume);
+
+        UpdateActualAmountParam tradeParam = new UpdateActualAmountParam();
+        tradeParam.setTOrderId(tradeOrder.getId());
+        tradeParam.setActualLoadAmount(totalLoadVolume);
+        tradeOrderInfoService.updateOrderActualAmount(tradeParam);
+        log.info("更新上游贸易订单运输量成功, 贸易订单ID:{}", tradeOrder.getId());
+    }
+
+
+    /**
+     * 回写物流订单数据
+     * @param logOrder
+     */
+    private void updateLogOrder(KwtLogisticsOrder logOrder, BigDecimal truckLoadVolume) {
+        log.info("更新上游物流运输量数据,logOrderId:{}", logOrder);
+        // 计算当前车辆总运输量
+        BigDecimal totalLoadVolume = Optional.ofNullable(logOrder.getEntrustAmount())
+                .map(entrust -> entrust.add(truckLoadVolume))
+                .orElse(truckLoadVolume);
+
+        logOrder.setEntrustAmount(totalLoadVolume);
+        logisticsOrderRepository.updateById(logOrder);
+        log.info("更新上游物流运输量成功, 物流订单ID:{}", logOrder.getId());
+    }
+
+    /**
+     * 装卸货地址
+     * @param logOrderIdList
+     * @return
+     */
+    private Map<String, KwtLogisticsOrderAddress> getKwtLogisticsOrderAddressMap(List<Long> logOrderIdList) {
+        List<KwtLogisticsOrderAddress> logOrderAddressList = logisticsOrderAddressRepository.queryByLogOrderIds(logOrderIdList);
+        if (CollectionUtils.isEmpty(logOrderAddressList)) {
+            log.info("物流订单无装卸货地址信息,logOrderIdList:{}", JSON.toJSONString(logOrderIdList));
+            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_ADDRESS, "物流订单无装卸货地址信息");
+        }
+        return logOrderAddressList.stream().collect(Collectors
+                .toMap(address -> address.getLOrderId() + "-" + address.getType(),
+                        Function.identity(), (x, y) -> x));
+    }
+
+    @Override
+    protected void updateStatus(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder) {
+        // 接单时运单已创建并设置初始状态(PENDING_VEHICLE)
+    }
+
+
+    @Override
+    protected String getProcessName() {
+        return "接单";
+    }
+
+    // 7. 接单单独创建接单轨迹数据
+    protected void afterProcess(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder) {
+        log.info("创建车辆运单-节点轨迹入参参数:{}", JSON.toJSONString(param));
+        KwtWaybillOrderSubtask waybillSubtask = getWaybillSubtask(waybillOrder.getId());
+        KwtWaybillOrderNode orderNode = new KwtWaybillOrderNode();
+        orderNode.setWOrderId(waybillOrder.getId());
+        orderNode.setWSubtaskId(waybillSubtask.getWOrderId());
+        orderNode.setOrderStatus(waybillOrder.getStatus());
+        orderNode.setTruckId(waybillOrder.getTruckId());
+        orderNode.setTruckNo(waybillOrder.getTruckNo());
+        orderNode.setDriverId(waybillOrder.getDriverId());
+        orderNode.setDriverName(waybillOrder.getDriverName());
+        orderNode.setLng(param.getLng());
+        orderNode.setLat(param.getLat());
+        waybillOrderNodeRepository.save(orderNode);
+        log.info("创建车辆运单-节点轨迹成功,节点轨迹ID:{}", orderNode.getId());
+    }
+}

+ 67 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/handler/UnloadingHandler.java

@@ -0,0 +1,67 @@
+package com.sckw.transport.handler;
+
+
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import com.sckw.core.exception.BusinessPlatfromException;
+import com.sckw.core.model.enums.CarWaybillV1Enum;
+import com.sckw.transport.model.KwtWaybillOrder;
+import com.sckw.transport.model.KwtWaybillOrderSubtask;
+import com.sckw.transport.model.param.WaybillOrderUnloadParam;
+import com.sckw.transport.repository.KwtWaybillOrderSubtaskRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * Author: donglang
+ * Time: 2025-11-19
+ * Des: 卸货
+ * Version: 1.0
+ */
+
+@Service
+public class UnloadingHandler extends AbstractWaybillOrderHandler<WaybillOrderUnloadParam>{
+
+    @Autowired
+    private KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
+
+
+    @Override
+    protected KwtWaybillOrder getWaybillOrder(WaybillOrderUnloadParam param) {
+        return getWaybillOrder(param.getWaybillOrderId());
+    }
+
+
+    @Override
+    protected void checkState(WaybillOrderUnloadParam param, KwtWaybillOrder waybill) {
+        if (waybill == null) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_FOUND, "运单不存在");
+        }
+        if (!Objects.equals(CarWaybillV1Enum.WAIT_LOADING.getCode(), waybill.getStatus())) {
+            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "当前物流运单不是已离场状态,无法推进下一节点!");
+        }
+    }
+
+    @Override
+    protected void doBusiness(WaybillOrderUnloadParam param, KwtWaybillOrder waybill) {
+        //更新子运单卸货净重  TODO 审核通过后,贸易订单和物流订单的运输量需要已实际卸货净重为准
+        KwtWaybillOrderSubtask subtask = getWaybillSubtask(waybill.getId());
+        subtask.setUnloadAmount(param.getUnloadAmount());
+        subtask.setUnloadTime(new Date());
+        waybillOrderSubtaskRepository.updateById(subtask);
+    }
+
+    @Override
+    protected void updateStatus(WaybillOrderUnloadParam param, KwtWaybillOrder waybill) {
+        // 已卸货状态
+        waybill.setStatus(CarWaybillV1Enum.COMPLETION_LOADING.getCode());
+        waybillOrderRepository.updateById(waybill);
+    }
+
+    @Override
+    protected String getProcessName() {
+        return "已卸货";
+    }
+}

+ 93 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/KwtWaybillOrderNode.java

@@ -0,0 +1,93 @@
+package com.sckw.transport.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author lfdc
+ * @description 车辆运单-节点轨迹
+ * @date 2023-06-26 16:06:12
+ */
+@Data
+@TableName("kwt_waybill_order_node")
+public class KwtWaybillOrderNode implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 8285698577702922580L;
+
+    /**
+     * 主键
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 车辆运单id
+     */
+    private Long wOrderId;
+
+    /**
+     * 运单关联子单ID
+     */
+    private Long wSubtaskId;
+
+    /**
+     * 运单状态
+     */
+    private Integer orderStatus;
+
+    /**
+     * 车辆id
+     */
+    private Long truckId;
+
+    /**
+     * 车牌号
+     */
+    private String truckNo;
+
+    /**
+     * 司机id
+     */
+    private Long driverId;
+
+    /**
+     * 司机名称
+     */
+    private String driverName;
+
+    /**
+     * 地磅id
+     */
+    private Long weighbridgeId;
+
+    /**
+     * 地磅名称
+     */
+    private String weighbridgeName;
+
+    /**
+     * 经度
+     */
+    private String lng;
+
+    /**
+     * 纬度
+     */
+    private String lat;
+
+    /**
+     * 创建人
+     */
+    private Long createBy;
+
+    /**
+     * 创建时间
+     */
+    private Data createTime;
+}

+ 5 - 41
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/KwtWaybillOrderTicket.java

@@ -1,9 +1,10 @@
 package com.sckw.transport.model;
 
-import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.sckw.core.model.base.BaseModel;
 import lombok.Data;
 
+import java.io.Serial;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Date;
@@ -15,12 +16,10 @@ import java.util.Date;
  */
 @Data
 @TableName("kwt_waybill_order_ticket")
-public class KwtWaybillOrderTicket implements Serializable {
+public class KwtWaybillOrderTicket extends BaseModel implements Serializable {
 
-    /**
-     * 主键
-     */
-    private Long id;
+    @Serial
+    private static final long serialVersionUID = -4606621905464045747L;
 
     /**
      * 车辆运单id
@@ -72,39 +71,4 @@ public class KwtWaybillOrderTicket implements Serializable {
      */
     private Date operateTime;
 
-    /**
-     * 状态(0待审核、1驳回、2审核成功)
-     */
-    private Integer status;
-
-    /**
-     * 备注
-     */
-    private String remark;
-
-    /**
-     * 创建人
-     */
-    private Long createBy;
-
-    /**
-     * 创建时间
-     */
-    private Date createTime;
-
-    /**
-     * 创建人更新人
-     */
-    private Long updateBy;
-    /**
-     * 更新时间
-     */
-    private Date updateTime;
-
-    /**
-     * 是否删除(0未删除,1删除)
-     */
-    private Integer delFlag;
-
-    private static final long serialVersionUID = 1L;
 }

+ 0 - 2
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/OrderCirculateQueryParam.java

@@ -36,6 +36,4 @@ public class OrderCirculateQueryParam extends PageReq implements Serializable {
     private String truckNo;
 
 
-
-
 }

+ 63 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/OrderCirculateTakingQueryParam.java

@@ -0,0 +1,63 @@
+package com.sckw.transport.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author :donglang
+ * @version :1.0
+ * @description :
+ * @create :2025-11-13 08:59:00
+ */
+@Data
+public class OrderCirculateTakingQueryParam extends WaybillOrderProcessParam implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 2488572282191939246L;
+    
+    /**
+     * 企业id
+     */
+    @Schema(description = "企业id")
+    @NotNull(message = "企业id不能为空!")
+    private Long entId;
+
+    /**
+     * 物流订单id
+     */
+    @Schema(description = "物流订单id")
+    @NotNull(message = "物流订单id不能为空!")
+    private Long logOrderId;
+
+    /**
+     * 车牌号
+     */
+    @Schema(description = "车牌号")
+    @NotBlank(message = "车牌号不能为空!")
+    private String truckNo;
+
+    /**
+     * 司机id
+     */
+    @Schema(description = "司机id")
+    @NotNull(message = "司机id不能为空!")
+    private Long driverId;
+
+    /**
+     * 经度
+     */
+    @NotBlank(message = "经度不能为空!")
+    private String lng;
+
+    /**
+     * 纬度
+     */
+    @NotBlank(message = "纬度不能为空!")
+    private String lat;
+
+}

+ 37 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderCancelParam.java

@@ -0,0 +1,37 @@
+package com.sckw.transport.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author :donglang
+ * @version :1.0
+ * @description :
+ * @create :2025-11-13 08:59:00
+ */
+@Data
+public class WaybillOrderCancelParam extends WaybillOrderProcessParam implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1038619782660342061L;
+    
+    /**
+     * 物流订单id
+     */
+    @Schema(description = "物流订单id")
+    @NotNull(message = "物流订单id不能为空!")
+    private Long logOrderId;
+
+    /**
+     * 运单id
+     */
+    @Schema(description = "运单id")
+    @NotBlank(message = "运单id不能为空!")
+    private Long waybillOrderId;
+
+}

+ 68 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderCmeIntoWeighParam.java

@@ -0,0 +1,68 @@
+package com.sckw.transport.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * @author :donglang
+ * @version :1.0
+ * @description : 车辆过磅入参信息
+ * @create :2025-11-13 08:59:00
+ */
+@Data
+public class WaybillOrderCmeIntoWeighParam extends WaybillOrderProcessParam implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1038619782660342061L;
+
+    /**
+     * 运单id
+     */
+    @Schema(description = "运单id")
+    @NotNull(message = "运单id不能为空")
+    private Long waybillOrderId;
+
+    /**
+     * 车辆号
+     */
+    @Schema(description = "车辆号")
+    @NotBlank(message = "车辆号不能为空")
+    private String truckNo;
+
+    /**
+     * 皮重
+     */
+    @Schema(description = "皮重")
+    @NotNull(message = "皮重不能为空")
+    private BigDecimal tareAmount;
+
+    /**
+     * 毛重
+     */
+    @Schema(description = "毛重")
+    @NotNull(message = "毛重不能为空")
+    private BigDecimal grossAmount;
+
+    /**
+     * 经度
+     */
+    @Schema(description = "经度")
+    @NotBlank(message = "经度不能为空")
+    private String lng;
+
+    /**
+     * 纬度
+     */
+    @Schema(description = "纬度")
+    @NotBlank(message = "纬度不能为空")
+    private String lat;
+
+
+
+}

+ 37 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderLeaveMockParam.java

@@ -0,0 +1,37 @@
+package com.sckw.transport.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * @author :donglang
+ * @version :1.0
+ * @description : 车辆过磅入参信息
+ * @create :2025-11-13 08:59:00
+ */
+@Data
+public class WaybillOrderLeaveMockParam extends WaybillOrderProcessParam implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 5785738912828986952L;
+
+    /**
+     * 运单id
+     */
+    @Schema(description = "运单id")
+    @NotNull(message = "运单id不能为空")
+    private Long waybillOrderId;
+
+    /**
+     * 毛重
+     */
+    @Schema(description = "毛重")
+    @NotNull(message = "毛重不能为空")
+    private BigDecimal grossAmount;
+
+}

+ 51 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderLeaveParam.java

@@ -0,0 +1,51 @@
+package com.sckw.transport.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author :donglang
+ * @version :1.0
+ * @description :
+ * @create :2025-11-13 08:59:00
+ */
+@Data
+public class WaybillOrderLeaveParam extends WaybillOrderProcessParam implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1038619782660342061L;
+
+    /**
+     * 物流订单id
+     */
+    @Schema(description = "物流订单id")
+    @NotNull(message = "物流订单id不能为空!")
+    private Long logOrderId;
+
+    /**
+     * 运单id
+     */
+    @Schema(description = "运单id")
+    @NotBlank(message = "运单id不能为空!")
+    private Long waybillOrderId;
+
+    /**
+     * 经度
+     */
+    @Schema(description = "经度")
+    @NotBlank(message = "经度不能为空!")
+    private String lng;
+
+    /**
+     * 纬度
+     */
+    @Schema(description = "纬度")
+    @NotBlank(message = "纬度不能为空!")
+    private String lat;
+
+}

+ 46 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderLoadingParam.java

@@ -0,0 +1,46 @@
+package com.sckw.transport.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author :donglang
+ * @version :1.0
+ * @description : 车辆装货入参信息
+ * @create :2025-11-13 08:59:00
+ */
+@Data
+public class WaybillOrderLoadingParam extends WaybillOrderProcessParam implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1038619782660342061L;
+
+    /**
+     * 运单id
+     */
+    @Schema(description = "运单id")
+    @NotNull(message = "运单id不能为空")
+    private Long waybillOrderId;
+
+    /**
+     * 经度
+     */
+    @Schema(description = "经度")
+    @NotBlank(message = "经度不能为空")
+    private String lng;
+
+    /**
+     * 纬度
+     */
+    @Schema(description = "纬度")
+    @NotBlank(message = "纬度不能为空")
+    private String lat;
+
+
+
+}

+ 44 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderProcessParam.java

@@ -0,0 +1,44 @@
+package com.sckw.transport.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * @author :donglang
+ * @version :1.0
+ * @description 参数基类
+ * @create :2025-11-13 08:59:00
+ */
+@Data
+public class WaybillOrderProcessParam implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = -114986619800571178L;
+
+    /**
+     * 运单id
+     */
+    @Schema(description = "运单id")
+    @NotNull(message = "运单id不能为空")
+    private Long waybillOrderId;
+
+    /**
+     * 经度
+     */
+    @Schema(description = "经度")
+    @NotBlank(message = "经度不能为空")
+    private String lng;
+
+    /**
+     * 纬度
+     */
+    @Schema(description = "纬度")
+    @NotBlank(message = "纬度不能为空")
+    private String lat;
+
+}

+ 67 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/model/param/WaybillOrderUnloadParam.java

@@ -0,0 +1,67 @@
+package com.sckw.transport.model.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * @author :donglang
+ * @version :1.0
+ * @description :
+ * @create :2025-11-13 08:59:00
+ */
+@Data
+public class WaybillOrderUnloadParam extends WaybillOrderProcessParam implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1038619782660342061L;
+
+    /**
+     * 物流订单id
+     */
+    @Schema(description = "物流订单id")
+    @NotNull(message = "物流订单id不能为空!")
+    private Long logOrderId;
+
+    /**
+     * 运单id
+     */
+    @Schema(description = "运单id")
+    @NotBlank(message = "运单id不能为空!")
+    private Long waybillOrderId;
+
+    /**
+     * 经度
+     */
+    @Schema(description = "经度")
+    @NotBlank(message = "经度不能为空!")
+    private String lng;
+
+    /**
+     * 纬度
+     */
+    @Schema(description = "纬度")
+    @NotBlank(message = "纬度不能为空!")
+    private String lat;
+
+    /**
+     * 卸货净重
+     */
+    @Schema(description = "卸货净重")
+    @NotBlank(message = "卸货净重不能为空!")
+    private BigDecimal unloadAmount;
+
+    /**
+     * 卸货凭证
+     */
+    @Schema(description = "卸货凭证")
+    @NotBlank(message = "卸货凭证不能为空!")
+    private String unloadUrl;
+
+
+}

+ 10 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtLogisticsOrderCirculateRepository.java

@@ -54,4 +54,14 @@ public class KwtLogisticsOrderCirculateRepository extends ServiceImpl<KwtLogisti
     public Boolean insertCirculates(List<KwtLogisticsOrderCirculate> insertOrderCirculates) {
        return saveBatch(insertOrderCirculates);
     }
+
+    public KwtLogisticsOrderCirculate findOneByLogOrderIdsAndTruckNo(Long logOrder, String truckNo, Long entId) {
+        return getOne(Wrappers.<KwtLogisticsOrderCirculate>lambdaQuery()
+                .eq(KwtLogisticsOrderCirculate::getDelFlag,0)
+                .eq(KwtLogisticsOrderCirculate::getLOrderId, logOrder)
+                .eq(Objects.nonNull(truckNo),KwtLogisticsOrderCirculate::getTruckNo, truckNo)
+                .eq(KwtLogisticsOrderCirculate::getEntId, entId)
+        );
+    }
+
 }

+ 2 - 2
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtLogisticsOrderRepository.java

@@ -84,10 +84,10 @@ public class KwtLogisticsOrderRepository extends ServiceImpl<KwtLogisticsOrderMa
        return updateById(updateLogisticsOrder);
     }
 
-    public KwtLogisticsOrder queryByLogOrderIdAndStatus(Long logOrderId) {
+    public KwtLogisticsOrder queryByLogOrderIdAndStatus(Long logOrderId, Integer code) {
         return getOne(Wrappers.<KwtLogisticsOrder>lambdaQuery()
                 .eq(KwtLogisticsOrder::getDelFlag,0)
                 .eq(KwtLogisticsOrder::getId, logOrderId)
-                .eq(KwtLogisticsOrder::getStatus, 15));
+                .eq(KwtLogisticsOrder::getStatus, code));
     }
 }

+ 0 - 2
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderAddressRepository.java

@@ -1,11 +1,9 @@
 package com.sckw.transport.repository;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sckw.transport.dao.KwtWaybillOrderAddressMapper;
 import com.sckw.transport.model.KwtWaybillOrderAddress;
-import jakarta.validation.constraints.NotNull;
 import org.springframework.stereotype.Repository;
 
 import java.util.List;

+ 15 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderNodeRepository.java

@@ -0,0 +1,15 @@
+package com.sckw.transport.repository;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sckw.transport.dao.KwtWaybillOrderNodeMapper;
+import com.sckw.transport.model.KwtWaybillOrderNode;
+import org.springframework.stereotype.Repository;
+
+
+/**
+ * @author PC
+ */
+@Repository
+public class KwtWaybillOrderNodeRepository extends ServiceImpl<KwtWaybillOrderNodeMapper, KwtWaybillOrderNode> {
+
+}

+ 8 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderRepository.java

@@ -146,4 +146,12 @@ public class KwtWaybillOrderRepository extends ServiceImpl<KwtWaybillOrderMapper
                 .last("limit 1")
         );
     }
+
+    public List<KwtWaybillOrder> findWbOrderByTruckNo(String truckNo) {
+        return list(Wrappers.<KwtWaybillOrder>lambdaQuery()
+                .eq(KwtWaybillOrder::getDelFlag,0)
+                .eq(KwtWaybillOrder::getTruckNo,truckNo)
+                .orderByDesc(KwtWaybillOrder::getId));
+    }
+
 }

+ 6 - 1
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderSubtaskRepository.java

@@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sckw.core.model.base.BaseModel;
 import com.sckw.transport.dao.KwtWaybillOrderSubtaskMapper;
 import com.sckw.transport.model.KwtWaybillOrderSubtask;
-import jakarta.validation.constraints.NotBlank;
 import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.stereotype.Repository;
 
@@ -47,6 +46,12 @@ public class KwtWaybillOrderSubtaskRepository extends ServiceImpl<KwtWaybillOrde
                 .in(KwtWaybillOrderSubtask::getWOrderId,wOrderIds));
     }
 
+    public KwtWaybillOrderSubtask queryByWOrderId(Long wOrderId) {
+        return getOne(Wrappers.<KwtWaybillOrderSubtask>lambdaQuery()
+                .eq(KwtWaybillOrderSubtask::getWOrderId,wOrderId)
+                .eq(BaseModel::getDelFlag,0));
+    }
+
     public List<KwtWaybillOrderSubtask> queryByLogIds(List<Long> logIds) {
         return list(Wrappers.<KwtWaybillOrderSubtask>lambdaQuery()
                 .eq(BaseModel::getDelFlag,0)

+ 24 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/repository/KwtWaybillOrderTicketRepository.java

@@ -0,0 +1,24 @@
+package com.sckw.transport.repository;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sckw.transport.dao.KwtWaybillOrderTicketMapper;
+import com.sckw.transport.model.KwtWaybillOrderTicket;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+
+/**
+ * @author PC
+ */
+@Repository
+public class KwtWaybillOrderTicketRepository extends ServiceImpl<KwtWaybillOrderTicketMapper, KwtWaybillOrderTicket> {
+
+    public List<KwtWaybillOrderTicket> queryByWOrderId(Long wOrderId) {
+        return list(Wrappers.<KwtWaybillOrderTicket>lambdaQuery()
+                .eq(KwtWaybillOrderTicket::getWOrderId,wOrderId)
+                .eq(KwtWaybillOrderTicket::getDelFlag,0));
+    }
+
+}

+ 62 - 36
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/KwtLogisticsConsignmentService.java

@@ -1,6 +1,7 @@
 package com.sckw.transport.service;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ArrayUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
@@ -18,8 +19,9 @@ import com.sckw.contract.api.RemoteContractService;
 import com.sckw.contract.api.model.dto.res.ContractCommonInfoResDto;
 import com.sckw.core.common.enums.enums.DictEnum;
 import com.sckw.core.common.enums.enums.DictTypeEnum;
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
 import com.sckw.core.exception.BusinessException;
-import com.sckw.core.exception.SystemException;
+import com.sckw.core.exception.BusinessPlatfromException;
 import com.sckw.core.model.constant.Global;
 import com.sckw.core.model.constant.NumberConstant;
 import com.sckw.core.model.enums.*;
@@ -163,9 +165,20 @@ public class KwtLogisticsConsignmentService {
     private final KwtLogisticsOrderUnitRepository logisticsOrderUnitRepository;
     private final KwtLogisticsOrderAddressRepository logisticsOrderAddressRepository;
     private final KwtLogisticsOrderContractRepository logisticsOrderContractRepository;
-    private final KwtWaybillOrderSubtaskRepository logisticsOrderSubtaskRepository;
+    private final KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
     private final KwtWaybillOrderRepository waybillOrderRepository;
     private final KwtLogisticsOrderCirculateRepository logisticsOrderCirculateRepository;
+    private final KwtWaybillOrderAddressRepository waybillOrderAddressRepository;
+    private final KwtWaybillOrderTicketRepository waybillOrderTicketRepository;
+    private final KwtWaybillOrderNodeRepository waybillOrderNodeRepository;
+
+    // 定义禁止运单接单的状态集合
+    private static final Set<Integer> FORBIDDEN_STATUSES = Set.of(1, 5, 10, 15, 30);
+    //载重任务量浮动吨数
+    private static final BigDecimal TWO_TONS = new BigDecimal("2");
+    //载重任务量计算比例
+    private static final BigDecimal EIGHTY_PERCENT = new BigDecimal("0.8");
+
     /**
      * 采购订单-物流托运生成托运订单
      *
@@ -2477,7 +2490,7 @@ public class KwtLogisticsConsignmentService {
         }
 
         //根据物流订单号查询运单信息
-        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = logisticsOrderSubtaskRepository.queryByLogId(logisticsOrder.getId());
+        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = waybillOrderSubtaskRepository.queryByLogId(logisticsOrder.getId());
 
         //获取返回信息
         return getLogisticsOrderDetailResp(orderContract, logOrderIdUnitTypeKeyAndUnitMap, logisticsOrder, kwpGoods,
@@ -2604,7 +2617,7 @@ public class KwtLogisticsConsignmentService {
         }
         //通过物流订单号查询运单
 
-        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = logisticsOrderSubtaskRepository.queryByLogId(kwtLogisticsOrder.getId());
+        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = waybillOrderSubtaskRepository.queryByLogId(kwtLogisticsOrder.getId());
         if (org.apache.commons.collections4.CollectionUtils.isEmpty(waybillOrderSubtasks)) {
             return PageDataResult.empty(req.getPageNum(), req.getPageSize());
         }
@@ -2687,7 +2700,7 @@ public class KwtLogisticsConsignmentService {
                     .collect(Collectors.toMap(RTruckVo::getId, Function.identity(),(k1, k2)->k1));
         }
         //查询子运单信息
-        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = logisticsOrderSubtaskRepository.queryByLogId(logOrderId);
+        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = waybillOrderSubtaskRepository.queryByLogId(logOrderId);
         Set<Long> billOrderIds = Sets.newHashSet();
         if (CollectionUtils.isNotEmpty(waybillOrderSubtasks)){
             //获取主运单id
@@ -2860,7 +2873,7 @@ public class KwtLogisticsConsignmentService {
         }
 
         //查询物流订单下的所有运单
-        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = logisticsOrderSubtaskRepository.queryByLogId(logOrderId);
+        List<KwtWaybillOrderSubtask> waybillOrderSubtasks = waybillOrderSubtaskRepository.queryByLogId(logOrderId);
         if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(waybillOrderSubtasks) && Objects.equals(logisticsOrder.getStatus(), LogisticsOrderV1Enum.IN_TRANSIT.getCode())){
             boolean b = waybillOrderSubtasks.stream().anyMatch(x -> !Objects.equals(x.getStatus(),
                     CarWaybillV1Enum.WAIT_UNLOADING.getCode()) || !Objects.equals(x.getStatus(),
@@ -2926,7 +2939,6 @@ public class KwtLogisticsConsignmentService {
      */
     public PageDataResult<LogisticsOrderResp> queryTruckLogisticsOrder(OrderCirculateQueryParam param) {
         log.info("查询司机关联车辆的物流订单:{}", JSON.toJSONString(param));
-
         LambdaQueryWrapper<KwtLogisticsOrderCirculate> queryWrapper = Wrappers.<KwtLogisticsOrderCirculate>lambdaQuery()
                 .eq(KwtLogisticsOrderCirculate::getEntId, param.getEntId())
                 .eq(KwtLogisticsOrderCirculate::getTruckNo, param.getTruckNo())
@@ -2950,39 +2962,53 @@ public class KwtLogisticsConsignmentService {
         //物流订单
         List<KwtLogisticsOrder> logOrderList = logisticsOrderRepository.queryByLogisticsOrderIds(logOrderIdList);
         if (CollectionUtils.isEmpty(logOrderList)) {
-            log.info("当前车辆辆的无物流订单,truckNo:{}", param.getTruckNo());
-            return PageDataResult.empty(param.getPageNum(), param.getPageSize());
+            log.info("当前车辆无物流订单,truckNo:{}", param.getTruckNo());
+            throw new BusinessPlatfromException(ErrorCodeEnum.DRIVER_STATUS_ERROR, "当前车辆无物流订单");
         }
 
         //商品
-        List<KwtLogisticsOrderGoods> kwtLogisticsOrderGoods = logisticsOrderGoodsRepository.queryByLogOrderIds(logOrderIdList);
+        List<KwtLogisticsOrderGoods> logOrderGoods = logisticsOrderGoodsRepository.queryByLogOrderIds(logOrderIdList);
+        if (CollectionUtils.isEmpty(logOrderGoods)) {
+            log.info("当前车辆的物流订单无商品信息,truckNo:{}", param.getTruckNo());
+            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_GOODS, "当前车辆的物流订单无商品信息");
+        }
+
         //物流id映射物流商品
-        Map<Long, KwtLogisticsOrderGoods> logOrderIdAndGoodsMap = kwtLogisticsOrderGoods.stream().collect(Collectors.toMap(KwtLogisticsOrderGoods::getLOrderId,
+        Map<Long, KwtLogisticsOrderGoods> logOrderIdAndGoodsMap = logOrderGoods.stream().collect(Collectors.toMap(KwtLogisticsOrderGoods::getLOrderId,
                 Function.identity(), (x, y) -> x));
+        List<Long> goodsIds = logOrderGoods.stream().map(KwtLogisticsOrderGoods::getGoodsId).distinct().collect(Collectors.toList());
 
-        List<Long> goodsIds = kwtLogisticsOrderGoods.stream().map(KwtLogisticsOrderGoods::getGoodsId).distinct().collect(Collectors.toList());
-        //商品id映射商品
+        //交易商品信息
         Map<Long, KwpGoods> goodsIdAndGoodsMap = goodsInfoService.getGoodsByIds(goodsIds);
+        if (MapUtil.isEmpty(goodsIdAndGoodsMap)) {
+            log.info("物流订单无关联商品信息,logOrderId:{}", JSON.toJSONString(logOrderIdList));
+            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_GOODS, "物流订单无关联商品信息");
+        }
 
         //承运托运企业
-        List<KwtLogisticsOrderUnit> kwtLogisticsOrderUnits = logisticsOrderUnitRepository.queryByLogOrderIds(logOrderIdList);
-        Map<String, KwtLogisticsOrderUnit> logOrderIdAndUnitMap = kwtLogisticsOrderUnits.stream()
+        List<KwtLogisticsOrderUnit> logOrderUnits = logisticsOrderUnitRepository.queryByLogOrderIds(logOrderIdList);
+        if (CollectionUtils.isEmpty(logOrderUnits)) {
+            log.info("物流订单无关联承运托运企业,logOrderId:{}", JSON.toJSONString(logOrderIdList));
+            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_ENT, "物流订单无关联承运托运企业");
+        }
+        Map<String, KwtLogisticsOrderUnit> logOrderIdAndUnitMap = logOrderUnits.stream()
                 .collect(Collectors.toMap(unit -> unit.getLOrderId() + "-" + unit.getUnitType(),
                         Function.identity(), (x, y) -> x));
 
         //供应企业
         Set<Long> tradeOrderIds = logOrderList.stream().map(KwtLogisticsOrder::getTOrderId).collect(Collectors.toSet());
-        //交易订单Map
         List<OrderUnitInfoDetailVO> orderUnitDetailVOS = tradeOrderInfoService.queryOrderUnitInfByTOrderId(tradeOrderIds);
+        if (CollectionUtils.isEmpty(orderUnitDetailVOS)) {
+            log.info("交易订单无关联采取/销售企业,tradeOrderIds:{}", JSON.toJSONString(tradeOrderIds));
+            throw new BusinessPlatfromException(ErrorCodeEnum.TRADE_ORDER_NOT_ENT, "交易订单无关联采取/销售企业");
+        }
+        //交易订单Map
         Map<String, OrderUnitInfoDetailVO> tOrderIdAndUnitMap = orderUnitDetailVOS.stream()
                 .collect(Collectors.toMap(unit -> unit.getTOrderId() + "-" + unit.getUnitType(),
                         Function.identity(), (x, y) -> x));
 
         //地址
-        List<KwtLogisticsOrderAddress> logOrderAddressList = logisticsOrderAddressRepository.queryByLogOrderIds(logOrderIdList);
-        Map<String, KwtLogisticsOrderAddress> logOrderIdAndAddressMap = logOrderAddressList.stream()
-                .collect(Collectors.toMap(address -> address.getLOrderId() + "-" + address.getType(),
-                        Function.identity(), (x, y) -> x));
+        Map<String, KwtLogisticsOrderAddress> logOrderIdAndAddressMap = getKwtLogisticsOrderAddressMap(logOrderIdList);
 
         //组装数据
         List<LogisticsOrderResp> ordderList = logOrderList.stream()
@@ -2994,6 +3020,22 @@ public class KwtLogisticsConsignmentService {
         return PageDataResult.success(param.getPageNum(), param.getPageSize(), (long) ordderList.size(), ordderList);
     }
 
+    /**
+     * 装卸货地址
+     * @param logOrderIdList
+     * @return
+     */
+    private Map<String, KwtLogisticsOrderAddress> getKwtLogisticsOrderAddressMap(List<Long> logOrderIdList) {
+        List<KwtLogisticsOrderAddress> logOrderAddressList = logisticsOrderAddressRepository.queryByLogOrderIds(logOrderIdList);
+        if (CollectionUtils.isEmpty(logOrderAddressList)) {
+            log.info("物流订单无装卸货地址信息,logOrderIdList:{}", JSON.toJSONString(logOrderIdList));
+            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_ADDRESS, "物流订单无装卸货地址信息");
+        }
+        return logOrderAddressList.stream().collect(Collectors
+                .toMap(address -> address.getLOrderId() + "-" + address.getType(),
+                        Function.identity(), (x, y) -> x));
+    }
+
     /**
      * 组装订单列表信息
      * @param order
@@ -3061,20 +3103,4 @@ public class KwtLogisticsConsignmentService {
     }
 
 
-    /**
-     * 物流订单接单
-     * @param param
-     * @return
-     */
-    public void orderTaking(Long LogOrderId){
-        log.info("物流订单接单入参参数:{}", LogOrderId);
-        //校验
-        KwtLogisticsOrder order = logisticsOrderRepository.queryByLogOrderIdAndStatus(LogOrderId);
-        if (order == null) {
-            log.info("当前物流订单不是可接单状态:{}", LogOrderId);
-            throw new SystemException(HttpStatus.QUERY_FAIL_CODE, HttpStatus.LOG_ORDER_TAKING);
-        }
-
-
-    }
 }

+ 2 - 1
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/KwtWaybillOrderV1Service.java

@@ -440,7 +440,8 @@ public class KwtWaybillOrderV1Service {
         for (WaybillOrderSelectVo waybillOrder : list) {
             RTruckVo truck = remoteFleetService.findTruck(waybillOrder.getTruckId());
             if (truck != null) {
-                waybillOrder.setActualWeight(truck.getActualWeight());
+                Double actualWeight = Optional.ofNullable(truck.getActualWeight()).map(BigDecimal::doubleValue).orElse(0.0);
+                waybillOrder.setActualWeight(actualWeight);
             }
         }
         return PageHelperUtil.getPageResult(new PageInfo<>(list));

+ 900 - 0
sckw-modules/sckw-transport/src/main/java/com/sckw/transport/service/app/WaybillOrderService.java

@@ -0,0 +1,900 @@
+package com.sckw.transport.service.app;
+
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.google.common.collect.Lists;
+import com.sckw.contract.api.RemoteContractService;
+import com.sckw.core.common.enums.enums.ErrorCodeEnum;
+import com.sckw.core.exception.BusinessPlatfromException;
+import com.sckw.core.model.constant.Global;
+import com.sckw.core.model.enums.AddressTypeEnum;
+import com.sckw.core.model.enums.CarWaybillV1Enum;
+import com.sckw.core.model.enums.LogisticsOrderV1Enum;
+import com.sckw.core.utils.CollectionUtils;
+import com.sckw.fleet.api.RemoteFleetService;
+import com.sckw.fleet.api.model.vo.RDriverVo;
+import com.sckw.fleet.api.model.vo.RTruckVo;
+import com.sckw.order.api.dubbo.RemoteTradeOrderAmountService;
+import com.sckw.order.api.dubbo.TradeOrderInfoService;
+import com.sckw.order.api.model.OrderDetailVo;
+import com.sckw.order.api.model.UpdateActualAmountParam;
+import com.sckw.product.api.dubbo.GoodsInfoService;
+import com.sckw.redis.config.RedisLockUtil;
+import com.sckw.system.api.RemoteSystemService;
+import com.sckw.transport.common.config.MessageUrlConfig;
+import com.sckw.transport.dao.*;
+import com.sckw.transport.handler.*;
+import com.sckw.transport.model.*;
+import com.sckw.transport.model.param.*;
+import com.sckw.transport.repository.*;
+import com.sckw.transport.service.*;
+import jakarta.annotation.Resource;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.stream.function.StreamBridge;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author zk
+ * @desc 司机app接单Service
+ * @date 2023/7/19 0019
+ */
+@Slf4j
+@Service
+@SuppressWarnings("all")
+@RequiredArgsConstructor
+public class WaybillOrderService {
+
+    private final KwtLogisticsOrderRepository logisticsOrderRepository;
+    private final KwtLogisticsOrderAddressRepository logisticsOrderAddressRepository;
+    private final KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
+    private final KwtWaybillOrderRepository waybillOrderRepository;
+    private final KwtWaybillOrderAddressRepository waybillOrderAddressRepository;
+    private final KwtWaybillOrderTicketRepository waybillOrderTicketRepository;
+    private final KwtWaybillOrderNodeRepository waybillOrderNodeRepository;
+
+    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 80000)
+    TradeOrderInfoService tradeOrderInfoService;
+
+    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
+    RemoteFleetService remoteFleetService;
+
+    private final TakingOrderHandler takingOrderHandler;
+    private final CancelHandler cancelHandler;
+    private final ComeIntoHandler comeIntoHandler;
+    private final LoadingHandler loadingHandler;
+    private final LeaveMockHandler leaveMockHandler;
+    private final LeaveHandler leaveHandler;
+    private final UnloadingHandler unloadingHandler;
+
+    //载重任务量浮动吨数
+    private static final BigDecimal TWO_TONS = new BigDecimal("2");
+    //载重任务量计算比例
+    private static final BigDecimal EIGHTY_PERCENT = new BigDecimal("0.8");
+    // 定义禁止运单接单的状态集合
+    private static final List<Integer> FORBIDDEN_STATUSES = Arrays.asList(
+            CarWaybillV1Enum.PENDING_VEHICLE.getCode(),
+            CarWaybillV1Enum.REFUSE_TRAFFIC.getCode(),
+            CarWaybillV1Enum.EXIT_COMPLETED.getCode(),
+            CarWaybillV1Enum.WAIT_LOADING.getCode(),
+            CarWaybillV1Enum.COMPLETION_UNLOADING.getCode()
+    );
+
+
+    /**
+     * 物流订单接单
+     * @param param
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void orderTaking(OrderCirculateTakingQueryParam param) {
+        takingOrderHandler.handler(param);
+    }
+
+    /**
+     * 取消订单接单
+     * @param param
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void cancelWaybillOrder(WaybillOrderCancelParam param) {
+        cancelHandler.handler(param);
+    }
+
+    /**
+     * 到达装货地点-手动推推送数据
+     * @param param
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void comeInto(WaybillOrderCmeIntoWeighParam param) {
+        comeIntoHandler.handler(param);
+    }
+
+    /**
+     * 已装货 -手动推推送数据
+     * @param param
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void loading(WaybillOrderLoadingParam param) {
+        loadingHandler.handler(param);
+    }
+
+    /**
+     * 场过磅(计算毛重和净重)-手动推推送数据
+     * @param param
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void leave(WaybillOrderLeaveMockParam param) {
+        leaveMockHandler.handler(param);
+    }
+
+    /**
+     * 离场
+     * @param param
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void leavedWaybillOrder(WaybillOrderLeaveParam param) {
+        leaveHandler.handler(param);
+    }
+
+    /**
+     * 卸货
+     * @param param
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void unloadingWaybillOrder(WaybillOrderUnloadParam param) {
+        unloadingHandler.handler(param);
+    }
+
+
+
+//    /**
+//     * 物流订单接单
+//     * @param param
+//     * @return
+//     */
+//    @Transactional(rollbackFor = Exception.class)
+//    public void orderTaking(OrderCirculateTakingQueryParam param){
+//        log.info("物流订单接单入参参数:{}", JSON.toJSONString(param));
+//
+//        //1.校验物流订单
+//        KwtLogisticsOrder logOrder = checkLogOrder(param);
+//        //2.校验交易订单
+//        OrderDetailVo orderDetail = checkTradeOrder(param, logOrder);
+//        //3.校验司机
+//        RDriverVo driver = checkDriver(param);
+//        //4.校验车辆
+//        RTruckVo truckNo = checkTruck(param);
+//        //5.校验车辆是否已有未完成运单
+//        checkTruckUnfinished(param);
+//
+//        //计算任务量(含接单校验)
+//        BigDecimal turckLoadVolume = queryCurTruckLoadVolume(truckNo, orderDetail);
+//
+//
+//        //创建运单及关联数据
+//
+//        //1、生成物流运单
+//        KwtWaybillOrder waybillOrder = createWaybillOrder(param, driver, truckNo);
+//
+//        //2、生成物流子运单
+//        KwtWaybillOrderSubtask waybillOrderSubtask = createWaybillOrderSubtask(param, waybillOrder, turckLoadVolume);
+//
+//        //3、生成物流运单地址
+//        List<KwtWaybillOrderAddress> waybillOrderAdderessList = createWaybillOrderAddress(param, waybillOrder, waybillOrderSubtask);
+//
+//        //4、生成车辆运单-装卸货信息
+//        createWaybillOrderTicket(param, logOrder, waybillOrder, waybillOrderSubtask, waybillOrderAdderessList, truckNo);
+//
+//        //5.生成车运单接单节点轨迹
+//        createWaybillOrderNode(param, waybillOrder, waybillOrderSubtask);
+//
+//        //6、更新上游订单:回写贸易订单
+//        updateTradeOrder(orderDetail, turckLoadVolume);
+//
+//        //7、更新上游订单:回写物流订单
+//        updateLogOrder(logOrder, turckLoadVolume);
+//
+//        log.info("物流订单接单完成,运单ID:{}", waybillOrder.getId());
+//
+//    }
+//
+//
+//
+//    /**
+//     * 校验物流订单是否是可接单状态
+//     * @param param
+//     * @return
+//     */
+//    private KwtLogisticsOrder checkLogOrder(OrderCirculateTakingQueryParam param) {
+//        KwtLogisticsOrder logOrder = logisticsOrderRepository.queryByLogOrderIdAndStatus(param.getLogOrderId(), LogisticsOrderV1Enum.IN_TRANSIT.getCode());
+//        if (logOrder == null) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_STATUS_ERROR, "物流订单非可接单状态");
+//        }
+//        return logOrder;
+//    }
+//
+//    /**
+//     * 校验交易订单状态
+//     * @param param
+//     * @param logOrder
+//     * @return
+//     */
+//    private OrderDetailVo checkTradeOrder(OrderCirculateTakingQueryParam param, KwtLogisticsOrder logOrder) {
+//        OrderDetailVo orderDetail = tradeOrderInfoService.queryByTradeOrderId(logOrder.getTOrderId());
+//        if (orderDetail == null || orderDetail.getStatus() == Global.NUMERICAL_ONE) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.TRADE_ORDER_STATUS_ERROR, "当前物流订单的交易订单已锁定");
+//        }
+//        return orderDetail;
+//    }
+//
+//    /**
+//     * 校验司机状态
+//     * @param param
+//     * @return
+//     */
+//    private RDriverVo checkDriver(OrderCirculateTakingQueryParam param) {
+//        RDriverVo driver = remoteFleetService.findDriver(param.getDriverId());
+//        if (driver == null || driver.getStatus() == Global.NUMERICAL_ONE) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.DRIVER_STATUS_ERROR, "当前司机已锁定");
+//        }
+//        return driver;
+//    }
+//
+//    /**
+//     * 校验车辆状态
+//     * @param param
+//     * @return
+//     */
+//    private RTruckVo checkTruck(OrderCirculateTakingQueryParam param) {
+//        RTruckVo truckNo = remoteFleetService.findTruckByTruckNo(param.getTruckNo());
+//        if (truckNo == null || truckNo.getStatus() == Global.NUMERICAL_ONE) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.TRUCK_STATUS_ERROR, "当前车辆已锁定");
+//        }
+//        return truckNo;
+//    }
+//
+//    /**
+//     * 校验车辆是否已有未完成运单(不可继续接单状态:已接单、已入场、已装货、已离场、审核驳回)
+//     * @param param
+//     */
+//    private void checkTruckUnfinished(OrderCirculateTakingQueryParam param) {
+//        List<KwtWaybillOrder> wbOrderByTruckNo = waybillOrderRepository.findWbOrderByTruckNo(param.getTruckNo());
+//        boolean hasForbidden  = wbOrderByTruckNo.stream()
+//                .anyMatch(order -> order != null && FORBIDDEN_STATUSES.contains(order.getStatus()));
+//        if (hasForbidden) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_UNFINISHED, "当前车辆有未完成的状态,不可继续接单");
+//        }
+//    }
+//
+//
+//    /**
+//     * 计算当前车辆任务量:
+//     * 若有皮重:任务量 = 核定载重 - 皮重
+//     * 若无皮重:任务量 = 核定载重 × 80%
+//     * <p>
+//     * 1.当订单余量>=车辆的(法定载重-首次皮重)且<(法定载重-首次皮重 + 2)时,接取的任务量为车辆的(法定载重-首次皮重);
+//     * 2.订单余量<车辆的(法定载重-首次皮重)时,该车辆无法接单;
+//     * 3.当订单余量>= (法定载重-首次皮重 + 2)时,接取的任务量为 (法定载重-首次皮重 + 2)
+//     *
+//     * @param param
+//     */
+//    private BigDecimal queryCurTruckLoadVolume(RTruckVo truckNo, OrderDetailVo orderDetailVo) {
+//        //核定载重
+//        BigDecimal actualWeight = truckNo.getActualWeight();
+//        if (actualWeight == null) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.RESOURCE_NOT_FOUND, "车辆核定载重不能为空!");
+//        }
+//        log.info("车辆核定载重:{}", actualWeight);
+//        //首次皮重
+//        BigDecimal tareWeight = truckNo.getTareWeight();
+//        //任务量
+//        BigDecimal loadVolume = BigDecimal.ZERO;
+//        if (tareWeight != null) {
+//            // 有皮重:任务量 = 核定载重 - 皮重
+//            loadVolume = actualWeight.subtract(tareWeight);
+//            log.info("车辆有皮重,皮重:{}, 任务量:{}", tareWeight, loadVolume);
+//
+//        } else {
+//            // 无皮重:任务量 = 核定载重 × 80%
+//            loadVolume = actualWeight.multiply(EIGHTY_PERCENT);
+//            log.info("车辆无皮重,按80%核定载重计算,车辆任务量:{}", loadVolume);
+//        }
+//
+//        //订单分配总量
+//        BigDecimal entrustAmount = orderDetailVo.getEntrustAmount();
+//        //订单实际交付量
+//        BigDecimal actualAmount = orderDetailVo.getActualAmount();
+//        if (entrustAmount == null || actualAmount == null) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "订单分配总量或订单实际交付量不能为空!");
+//        }
+//        //订单余量 = 分配总量 - 实际交付量
+//        BigDecimal remainingAmount = entrustAmount.subtract(actualAmount);
+//        log.info("订单余量 = 分配总量:{} - 实际交付量:{} = 车辆任务量:{}", entrustAmount, actualAmount, remainingAmount);
+//
+//        // 最终接取的任务量
+//        BigDecimal taskAmount;
+//        BigDecimal loadVolumePlus2 = loadVolume.add(TWO_TONS);
+//        if (remainingAmount.compareTo(loadVolume) < 0) {
+//            // 规则2:订单余量 < 任务量 → 无法接单
+//            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, String.format("订单余量不足,无法接单, 订单余量:%s, 车辆任务量:%s", remainingAmount, loadVolume));
+//        } else if (remainingAmount.compareTo(loadVolumePlus2) >= 0) {
+//            // 规则3:订单余量 >= 任务量+2 → 接取任务量+2
+//            taskAmount = loadVolumePlus2;
+//            log.info("订单余量充足,按(任务量+2吨)接单,最终任务量: {}", taskAmount);
+//        } else {
+//            // 规则1:订单余量 >= 任务量 且 < 任务量+2 → 接取任务量
+//            taskAmount = loadVolume;
+//            log.info("订单余量适中,按基础任务量接单,最终任务量: {}", taskAmount);
+//        }
+//        log.info("最终任务量:{}", remainingAmount);
+//        return taskAmount;
+//    }
+//
+//    /**
+//     * 创建物流运单
+//     *
+//     * @param param
+//     */
+//    private KwtWaybillOrder createWaybillOrder(OrderCirculateTakingQueryParam param, RDriverVo driver, RTruckVo truckNo) {
+//        log.info("创建物流运单入参参数:{}", JSON.toJSONString(param));
+//        KwtWaybillOrder waybillOrder = new KwtWaybillOrder();
+//
+//        waybillOrder.setEntId(param.getEntId());
+//        waybillOrder.setWOrderNo(null);
+//        waybillOrder.setType(1);
+//        waybillOrder.setTruckId(truckNo.getId());
+//        waybillOrder.setTruckNo(param.getTruckNo());
+//        waybillOrder.setDriverId(param.getDriverId());
+//        waybillOrder.setDriverName(driver.getName());
+//        waybillOrder.setDriverPhone(driver.getPhone());
+//        waybillOrder.setDriverIdcard(driver.getIdcard());
+//        waybillOrder.setStatus(CarWaybillV1Enum.PENDING_VEHICLE.getCode());
+//        waybillOrder.setTaskStartTime(new Date());
+//        waybillOrderRepository.save(waybillOrder);
+//        log.info("创建物流运单成功,运单ID:{}", waybillOrder.getId());
+//
+//        return waybillOrder;
+//
+//    }
+//
+//    /**
+//     * 创建物流子运单
+//     *
+//     * @param param
+//     */
+//    private KwtWaybillOrderSubtask createWaybillOrderSubtask(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder,
+//                                                             BigDecimal turckLoadVolume) {
+//        log.info("创建物流子运单入参参数:{}", JSON.toJSONString(param));
+//        KwtWaybillOrderSubtask subtask = new KwtWaybillOrderSubtask();
+//
+//        subtask.setEntId(param.getEntId());
+//        subtask.setLOrderId(param.getLogOrderId());
+//        subtask.setWOrderId(waybillOrder.getId());
+//        subtask.setWOrderNo(waybillOrder.getWOrderNo());
+//        subtask.setUnit(null);
+//
+//        subtask.setEntrustAmount(turckLoadVolume);
+//        subtask.setLoadTime(waybillOrder.getTaskStartTime());
+//        subtask.setUnloadTime(waybillOrder.getEndTime());
+//        subtask.setStatus(CarWaybillV1Enum.PENDING_VEHICLE.getCode());
+//        waybillOrderSubtaskRepository.save(subtask);
+//        log.info("创建物流子运单成功,子运单ID:{}", subtask.getId());
+//
+//        return subtask;
+//
+//    }
+//
+//    /**
+//     * 创建物流运单地址
+//     *
+//     * @param param
+//     */
+//    private List<KwtWaybillOrderAddress> createWaybillOrderAddress(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder,
+//                                                                    KwtWaybillOrderSubtask waybillOrderSubtask) {
+//        log.info("创建物流运单地址入参参数,logOrderId:{}", param.getLogOrderId());
+//        //地址
+//        Map<String, KwtLogisticsOrderAddress> logOrderIdAndAddressMap = getKwtLogisticsOrderAddressMap(Lists.newArrayList(param.getLogOrderId()));
+//        List<KwtWaybillOrderAddress> createdAddresses = new ArrayList<>();
+//
+//        //装货地址
+//        KwtLogisticsOrderAddress shipmentSource = logOrderIdAndAddressMap.getOrDefault(
+//                param.getLogOrderId() + "-" + AddressTypeEnum.SHIPMENT.getCode(), new KwtLogisticsOrderAddress());
+//        KwtWaybillOrderAddress shipmentAddress = createAddress(waybillOrder, waybillOrderSubtask, shipmentSource, AddressTypeEnum.SHIPMENT);
+//        createdAddresses.add(shipmentAddress);
+//        log.info("创建物流运单装货地址成功,运单地址ID:{}", shipmentAddress.getId());
+//
+//        //卸货地址
+//        KwtLogisticsOrderAddress takeSource = logOrderIdAndAddressMap.getOrDefault(
+//                param.getLogOrderId() + "-" + AddressTypeEnum.TAKE.getCode(), new KwtLogisticsOrderAddress());
+//        KwtWaybillOrderAddress takeAddress = createAddress(waybillOrder, waybillOrderSubtask, takeSource, AddressTypeEnum.TAKE);
+//        createdAddresses.add(takeAddress);
+//        log.info("创建物流运单卸货地址成功,运单地址ID:{}", takeAddress.getId());
+//
+//        log.info("成功创建{}个运单地址", createdAddresses.size());
+//        return createdAddresses;
+//    }
+//
+//    /**
+//     * 装卸货地址
+//     * @param logOrderIdList
+//     * @return
+//     */
+//    private Map<String, KwtLogisticsOrderAddress> getKwtLogisticsOrderAddressMap(List<Long> logOrderIdList) {
+//        List<KwtLogisticsOrderAddress> logOrderAddressList = logisticsOrderAddressRepository.queryByLogOrderIds(logOrderIdList);
+//        if (CollectionUtils.isEmpty(logOrderAddressList)) {
+//            log.info("物流订单无装卸货地址信息,logOrderIdList:{}", JSON.toJSONString(logOrderIdList));
+//            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_NOT_ADDRESS, "物流订单无装卸货地址信息");
+//        }
+//        return logOrderAddressList.stream().collect(Collectors
+//                .toMap(address -> address.getLOrderId() + "-" + address.getType(),
+//                        Function.identity(), (x, y) -> x));
+//    }
+//
+//    /**
+//     * 保存运单物流地址
+//     * @param waybillOrder
+//     * @param waybillOrderSubtask
+//     * @param shipmentAddress
+//     */
+//    private KwtWaybillOrderAddress createAddress(KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask subtask,
+//                                                 KwtLogisticsOrderAddress orderAddress, AddressTypeEnum typeEnum) {
+//        KwtWaybillOrderAddress address = new KwtWaybillOrderAddress();
+//        address.setWOrderId(waybillOrder.getId());
+//        address.setWSubtaskId(subtask.getId());
+//        address.setLAddressId(orderAddress.getId());
+//        address.setAddressType(typeEnum.getCode());
+//        address.setName(orderAddress.getName());
+//        address.setType(orderAddress.getType());
+//        address.setContacts(orderAddress.getContacts());
+//        address.setPhone(orderAddress.getPhone());
+//        address.setCityCode(orderAddress.getCityCode());
+//        address.setCityName(orderAddress.getCityName());
+//        address.setDetailAddress(orderAddress.getDetailAddress());
+//        address.setLat(orderAddress.getLat());
+//        address.setLng(orderAddress.getLng());
+//        address.setFence(orderAddress.getFence());
+//        address.setEntryType(orderAddress.getEntryType());
+//        address.setPlanTime(waybillOrder.getTaskStartTime());
+//        address.setSort(Global.NUMERICAL_ONE);
+//        address.setEntrustAmount(subtask.getEntrustAmount());
+//
+//        waybillOrderAddressRepository.save(address);
+//        return address;
+//
+//    }
+//
+//    /**
+//     * 生成车辆运单-装卸货信息
+//     *
+//     * @param param
+//     * @param waybillOrder
+//     */
+//    private void createWaybillOrderTicket(OrderCirculateTakingQueryParam param, KwtLogisticsOrder logOrder,
+//                                          KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask waybillOrderSubtask,
+//                                          List<KwtWaybillOrderAddress> waybillOrderAddresses, RTruckVo truckNo) {
+//        log.info("创建车辆运单-装卸货信息入参参数:{}", JSON.toJSONString(param));
+//
+//        //装货地址
+//        KwtWaybillOrderAddress shipmentAddress = getWaybillOrderAddress(waybillOrderAddresses, AddressTypeEnum.SHIPMENT);
+//        createTicket(waybillOrder, waybillOrderSubtask, shipmentAddress, logOrder, truckNo);
+//        log.info("创建车辆运单-装卸货信息成功!");
+//
+//        //卸货地址
+//        KwtWaybillOrderAddress takeAddress = getWaybillOrderAddress(waybillOrderAddresses, AddressTypeEnum.TAKE);
+//        createTicket(waybillOrder, waybillOrderSubtask, shipmentAddress, logOrder, truckNo);
+//        log.info("创建车辆运单-装卸货信息成功!");
+//
+//    }
+//
+//
+//    /**
+//     * 运单地址(装货、卸货地址)
+//     *
+//     * @param waybillOrderAddresses
+//     * @param typeEnum
+//     * @return
+//     */
+//    private KwtWaybillOrderAddress getWaybillOrderAddress(List<KwtWaybillOrderAddress> waybillOrderAddresses, AddressTypeEnum typeEnum) {
+//        return waybillOrderAddresses.stream()
+//                .filter(address -> address != null && typeEnum.getCode() == address.getType())
+//                .findFirst()
+//                .orElseThrow(() -> new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_ADDRESS_NOT_FOUND, "未找到装货地址数据!"));
+//    }
+//
+//    /**
+//     * 保存车辆运单-装卸货信息
+//     *
+//     * @param waybillOrder
+//     * @param waybillOrderSubtask
+//     * @param shipmentAddress
+//     */
+//    private void createTicket(KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask waybillOrderSubtask,
+//                              KwtWaybillOrderAddress shipmentAddress, KwtLogisticsOrder logOrder, RTruckVo truckNo) {
+//        KwtWaybillOrderTicket ticket = new KwtWaybillOrderTicket();
+//        ticket.setWOrderId(waybillOrder.getId());
+//        ticket.setWSubtaskId(waybillOrderSubtask.getId());
+//        ticket.setWAddressId(shipmentAddress.getId());
+//        ticket.setType(shipmentAddress.getAddressType());
+//        ticket.setUnit(logOrder.getUnit());
+//        ticket.setAmount(BigDecimal.ZERO);
+//        ticket.setGrossAmount(truckNo.getGrossWeight());
+//        ticket.setTareAmount(truckNo.getTareWeight());
+//        waybillOrderTicketRepository.save(ticket);
+//    }
+//
+//
+//    /**
+//     * 生成车辆运单-节点轨迹
+//     *
+//     * @param param
+//     * @param waybillOrder
+//     */
+//    private void createWaybillOrderNode(OrderCirculateTakingQueryParam param, KwtWaybillOrder waybillOrder, KwtWaybillOrderSubtask waybillOrderSubtask) {
+//        log.info("创建车辆运单-节点轨迹入参参数:{}", JSON.toJSONString(param));
+//        KwtWaybillOrderNode orderNode = new KwtWaybillOrderNode();
+//        orderNode.setWOrderId(waybillOrder.getId());
+//        orderNode.setWSubtaskId(waybillOrderSubtask.getWOrderId());
+//        orderNode.setOrderStatus(waybillOrder.getStatus());
+//        orderNode.setTruckId(waybillOrder.getTruckId());
+//        orderNode.setTruckNo(waybillOrder.getTruckNo());
+//        orderNode.setDriverId(waybillOrder.getDriverId());
+//        orderNode.setDriverName(waybillOrder.getDriverName());
+//        orderNode.setLng(param.getLng());
+//        orderNode.setLat(param.getLat());
+//        waybillOrderNodeRepository.save(orderNode);
+//        log.info("创建车辆运单-节点轨迹成功,节点轨迹ID:{}", orderNode.getId());
+//    }
+//
+//    /**
+//     * 回写贸易订单数据
+//     * @param param
+//     */
+//    private void updateTradeOrder(OrderDetailVo orderDetail, BigDecimal truckLoadVolume) {
+//        log.info("更新上游贸易订单运输量数据,tradeOrderId:{}", orderDetail.getId());
+//        // 计算当前车辆运输量
+//        BigDecimal totalLoadVolume = Optional.ofNullable(orderDetail.getActualAmount())
+//                .map(entrust -> entrust.add(truckLoadVolume))
+//                .orElse(truckLoadVolume);
+//
+//        UpdateActualAmountParam tradeParam = new UpdateActualAmountParam();
+//        tradeParam.setTOrderId(orderDetail.getId());
+//        tradeParam.setActualLoadAmount(totalLoadVolume);
+//        tradeOrderInfoService.updateOrderActualAmount(tradeParam);
+//        log.info("更新上游贸易订单运输量成功, 贸易订单ID:{}", orderDetail.getId());
+//    }
+//
+//
+//    /**
+//     * 回写物流订单数据
+//     * @param param
+//     */
+//    private void updateLogOrder(KwtLogisticsOrder logOrder, BigDecimal truckLoadVolume) {
+//        log.info("更新上游物流运输量数据,logOrderId:{}", logOrder);
+//        // 计算当前车辆总运输量
+//        BigDecimal totalLoadVolume = Optional.ofNullable(logOrder.getEntrustAmount())
+//                .map(entrust -> entrust.add(truckLoadVolume))
+//                .orElse(truckLoadVolume);
+//
+//        logOrder.setEntrustAmount(totalLoadVolume);
+//        logisticsOrderRepository.updateById(logOrder);
+//        log.info("更新上游物流运输量成功, 物流订单ID:{}", logOrder.getId());
+//    }
+//
+//    /**
+//     * 取消订单
+//     *
+//     * @param waybillOrderId
+//     * @return
+//     */
+//    public void cancelWaybillOrder(WaybillOrderCancelParam param) {
+//        log.info("取消订单接单入参参数:{}", JSON.toJSONString(param));
+//        //1.取消物流运单
+//        BigDecimal entrustAmount = updateWaybillOrder(param);
+//
+//        //2.更新上游订单:更新物流订单运输量
+//        KwtLogisticsOrder logOrder = updateLogOrder(param, entrustAmount);
+//
+//        //3.更新上游订单:更新贸易订单运输量
+//        updateTradeOrder(logOrder, entrustAmount);
+//
+//        log.info("取消接单成功!");
+//    }
+//
+//    /**
+//     * 更改物流运单状态
+//     * @param param
+//     * @return
+//     */
+//    private BigDecimal updateWaybillOrder(WaybillOrderCancelParam param) {
+//        KwtWaybillOrder waybillOrder = waybillOrderRepository.queryByBillOrderId(param.getWaybillOrderId());
+//        if (waybillOrder == null || CarWaybillV1Enum.PENDING_VEHICLE.getCode() != waybillOrder.getStatus()) {
+//            log.info("当前物流运单状态不可取消, waybillOrderId:{}", param.getWaybillOrderId());
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "当前物流运单状态不可取消!");
+//        }
+//        waybillOrder.setStatus(CarWaybillV1Enum.APPROVAL_TREAT.getCode());
+//        waybillOrderRepository.updateById(waybillOrder);
+//        log.info("取消物流运单成功, 物流运单ID:{}", waybillOrder.getId());
+//
+//        //车辆本次运输量
+//        KwtWaybillOrderSubtask orderSubtask = waybillOrderSubtaskRepository.queryByWOrderId(waybillOrder.getId());
+//        BigDecimal entrustAmount = orderSubtask.getEntrustAmount();
+//        return entrustAmount;
+//    }
+//
+//    /**
+//     * 更新上游物流订单 - 减运输量
+//     * @param param
+//     * @param entrustAmoun
+//     * @return
+//     */
+//    private KwtLogisticsOrder updateLogOrder(WaybillOrderCancelParam param, BigDecimal entrustAmount) {
+//        KwtLogisticsOrder logOrder = logisticsOrderRepository.queryByLogisticsOrderId(param.getLogOrderId());
+//        if (logOrder == null) {
+//            log.info("当前物流运单无关联物流订单数据:{}", param.getLogOrderId());
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_LOG_ORDER, "当前物流运单无关联物流订单数据!");
+//        }
+//
+//        //取消接单的物流订单的总运输量不能为空
+//        if (logOrder.getEntrustAmount() == null || logOrder.getEntrustAmount().compareTo(BigDecimal.ZERO) <= 0) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.LOGISTICS_ORDER_AMOUNT_ERROR, "已接单物订单的总运单量不能为空或0!");
+//        }
+//        logOrder.setEntrustAmount(logOrder.getEntrustAmount().subtract(entrustAmount));
+//        logisticsOrderRepository.updateById(logOrder);
+//        log.info("更新上游物流订单运输量成功, 物流订单ID:{}", logOrder.getId());
+//        return logOrder;
+//    }
+//
+//
+//    /**
+//     * 更新上游贸易订单 - 减运输量
+//     * @param logOrder
+//     * @param entrustAmount
+//     */
+//    private void updateTradeOrder(KwtLogisticsOrder logOrder, BigDecimal entrustAmount) {
+//        OrderDetailVo tradeOrder = tradeOrderInfoService.queryByTradeOrderId(logOrder.getTOrderId());
+//        //取消接单的物流订单的总运输量不能为空
+//        if (tradeOrder.getActualAmount() == null || tradeOrder.getActualAmount().compareTo(BigDecimal.ZERO) <= 0) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.TRADE_ORDER_AMOUNT_ERROR, "已接单交易订单的总运输量不能为空或0!");
+//        }
+//
+//        UpdateActualAmountParam tradeParam = new UpdateActualAmountParam();
+//        tradeParam.setTOrderId(tradeOrder.getId());
+//        tradeParam.setActualLoadAmount(tradeOrder.getActualAmount().subtract(entrustAmount));
+//        tradeOrderInfoService.updateOrderActualAmount(tradeParam);
+//        log.info("更新上游贸易订单运输量成功, 贸易订单ID:{}", tradeOrder.getId());
+//    }
+//
+//
+//    /**
+//     * 到达装货地点
+//     * @param waybillOrderId
+//     * @return
+//     */
+//    public void comeInto(WaybillOrderCmeIntoWeighParam param){
+//        log.info("推送物流运单状态到到达装货地点:{}", JSON.toJSONString(param));
+//        //1.修改物流运单状态-到达装货地点
+//        KwtWaybillOrder waybillOrder = updateWaybillOrderStayus(param.getWaybillOrderId(), CarWaybillV1Enum.PENDING_VEHICLE, CarWaybillV1Enum.REFUSE_TRAFFIC);
+//        waybillOrderRepository.updateById(waybillOrder);
+//
+//        //2.填充运单皮重
+//        LambdaQueryWrapper<KwtWaybillOrderTicket>  queryWrapper = Wrappers.<KwtWaybillOrderTicket>lambdaQuery()
+//                .eq(KwtWaybillOrderTicket::getWOrderId, param.getWaybillOrderId())
+//                .eq(KwtWaybillOrderTicket::getType, AddressTypeEnum.SHIPMENT.getCode());
+//        KwtWaybillOrderTicket orderTicket = waybillOrderTicketRepository.getOne(queryWrapper);
+//        orderTicket.setTareAmount(param.getTareAmount());
+//        waybillOrderTicketRepository.save(orderTicket);
+//
+//        //3.填充首次皮重
+//        RTruckVo truck = remoteFleetService.findTruckByTruckNo(param.getTruckNo());
+//        if (truck != null && truck.getTareWeight() == null) {
+//            RTruckVo truckNo = new RTruckVo();
+//            truckNo.setId(truck.getId());
+//            truckNo.setTareWeight(param.getTareAmount());
+//            remoteFleetService.updateTruckTareAmount(truckNo);
+//        }
+//        //4.生成到达装货地点节点轨迹
+//        createEnteredWaybillOrderNode(param.getLng(), param.getLat(), waybillOrder, CarWaybillV1Enum.REFUSE_TRAFFIC);
+//
+//        log.info("物流运单到达装货地点成功!");
+//    }
+//
+//    /**
+//     * 已装货
+//     * @param waybillOrderId
+//     * @return
+//     */
+//    public void loading(WaybillOrderLoadingParam param){
+//        log.info("推送物流运单状态到已装货:{}", JSON.toJSONString(param));
+//        //1.修改物流运单状态-已装货
+//        KwtWaybillOrder waybillOrder = updateWaybillOrderStayus(param.getWaybillOrderId(), CarWaybillV1Enum.REFUSE_TRAFFIC, CarWaybillV1Enum.EXIT_COMPLETED);
+//        waybillOrderRepository.updateById(waybillOrder);
+//
+//        //2.生成已已装货节点轨迹
+//        createEnteredWaybillOrderNode(param.getLng(), param.getLat(), waybillOrder, CarWaybillV1Enum.EXIT_COMPLETED);
+//        log.info("物流运单装货成功!");
+//    }
+//
+//    /**
+//     * 离场过磅-计算毛重和装货净重
+//     * @param waybillOrderId
+//     * @return
+//     */
+//    public void leave(WaybillOrderLeaveMockParam param){
+//        log.info("离场过磅-计算毛重和净重, 入参参数:{}", JSON.toJSONString(param));
+//        //校验运单状态
+//        KwtWaybillOrder waybillOrder = waybillOrderRepository.queryByBillOrderId(param.getWaybillOrderId());
+//        if (waybillOrder == null) {
+//            log.warn("物流运单不存在,waybillOrderId:{}", param.getWaybillOrderId());
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_FOUND, "物流运单不存在!");
+//        }
+//        if (CarWaybillV1Enum.EXIT_COMPLETED.getCode() != waybillOrder.getStatus()) {
+//            log.warn("运单状态不符合离场过磅条件,当前状态: {}, 要求状态: 已装货, waybillOrderId: {}", waybillOrder.getStatus(), waybillOrder.getId());
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "运单状态不符合离场过磅条件,无法推进下一节点!");
+//        }
+//
+//        //记录毛重和装货净重
+//        paddingGrossAndLoadAmount(param, waybillOrder);
+//    }
+//
+//    /**
+//     * 记录毛重和装货净重
+//     * @param param
+//     * @param waybillOrder
+//     */
+//    private void paddingGrossAndLoadAmount(WaybillOrderLeaveMockParam param, KwtWaybillOrder waybillOrder) {
+//        List<KwtWaybillOrderTicket> ticketList = waybillOrderTicketRepository.queryByWOrderId(param.getWaybillOrderId());
+//        // 按 type 分组
+//        Map<Integer, KwtWaybillOrderTicket> ticketMap = ticketList.stream()
+//                .collect(Collectors.toMap(KwtWaybillOrderTicket::getType, Function.identity(), (a, b) -> a));
+//        //1.填充毛重
+//        updateGrossAmount(param, ticketMap);
+//        //2.填充装货净重
+//        updateLoadAmount(param, waybillOrder, ticketMap);
+//    }
+//
+//    /**
+//     * 填充毛重
+//     * @param param
+//     * @param ticketMap
+//     */
+//    private void updateGrossAmount(WaybillOrderLeaveMockParam param, Map<Integer, KwtWaybillOrderTicket> ticketMap) {
+//        //查询卸货信息,用于记录毛重
+//        KwtWaybillOrderTicket takeTicket = ticketMap.getOrDefault(AddressTypeEnum.TAKE.getCode(), new KwtWaybillOrderTicket());
+//        if (takeTicket == null) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_TICKET_NOT_FOUND, "当前物流运单装卸货信息不存在,无法记录毛重!");
+//        }
+//        takeTicket.setGrossAmount(param.getGrossAmount());
+//        waybillOrderTicketRepository.updateById(takeTicket);
+//    }
+//
+//    /**
+//     * 填充装货净重
+//     * @param param
+//     * @param waybillOrder
+//     * @param ticketMap
+//     */
+//    private void updateLoadAmount(WaybillOrderLeaveMockParam param, KwtWaybillOrder waybillOrder, Map<Integer, KwtWaybillOrderTicket> ticketMap) {
+//        //查询卸货信息,用于获取皮重
+//        KwtWaybillOrderTicket shipmentTicket  = ticketMap.getOrDefault(AddressTypeEnum.SHIPMENT.getCode(), new KwtWaybillOrderTicket());
+//        if (shipmentTicket == null) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_TICKET_NOT_FOUND, "当前物流运单装卸货信息不存在,无法获取皮重!");
+//        }
+//        //皮重
+//        BigDecimal tareAmount = shipmentTicket.getTareAmount();
+//
+//        //更新子运单的装货净重
+//        KwtWaybillOrderSubtask subtask = waybillOrderSubtaskRepository.queryByWOrderId(waybillOrder.getId());
+//        if (subtask == null) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_SUB_NOT_FOUND, "未找到关联的子运单!");
+//        }
+//        BigDecimal loadAmount = param.getGrossAmount().subtract(Optional.ofNullable(tareAmount).orElse(BigDecimal.ZERO));
+//        subtask.setLoadAmount(loadAmount);
+//        subtask.setLoadTime(new Date());
+//        waybillOrderSubtaskRepository.updateById(subtask);
+//        log.info("物流运单离场过磅成功!运单ID: {}, 毛重: {}, 皮重: {}, 装货净重: {}", param.getWaybillOrderId(), param.getGrossAmount(), tareAmount, loadAmount);
+//    }
+//
+//
+//    /**
+//     * 离场
+//     * @param waybillOrderId
+//     * @return
+//     */
+//    public void leavedWaybillOrder(WaybillOrderLeaveParam param){
+//        log.info("推送物流运单状态到已离场:{}", JSON.toJSONString(param));
+//        //1.修改物流运单状态-离场
+//        KwtWaybillOrder waybillOrder = updateWaybillOrderStayus(param.getWaybillOrderId(), CarWaybillV1Enum.EXIT_COMPLETED, CarWaybillV1Enum.WAIT_LOADING);
+//        waybillOrderRepository.updateById(waybillOrder);
+//
+//        //2.生成已已装货节点轨迹
+//        createEnteredWaybillOrderNode(param.getLng(), param.getLat(), waybillOrder, CarWaybillV1Enum.WAIT_LOADING);
+//        log.info("物流运单离场成功!");
+//    }
+//
+//    /**
+//     * 卸货
+//     * @param waybillOrderId
+//     * @return
+//     */
+//    public void unloadingWaybillOrder(WaybillOrderUnloadParam param){
+//        log.info("推送物流运单状态到已卸货:{}", JSON.toJSONString(param));
+//        //1.修改物流运单状态-已卸货
+//        KwtWaybillOrder waybillOrder = updateWaybillOrderStayus(param.getWaybillOrderId(), CarWaybillV1Enum.WAIT_LOADING, CarWaybillV1Enum.COMPLETION_LOADING);
+//        waybillOrderRepository.updateById(waybillOrder);
+//
+//        //2.更新子运单卸货净重  TODO 审核通过后,贸易订单和物流订单的运输量需要已实际卸货净重为准
+//        KwtWaybillOrderSubtask subtask = waybillOrderSubtaskRepository.queryByWOrderId(waybillOrder.getId());
+//        if (subtask == null) {
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_SUB_NOT_FOUND, "未找到关联的子运单!");
+//        }
+//        subtask.setUnloadAmount(param.getUnloadAmount());
+//        subtask.setUnloadTime(new Date());
+//        waybillOrderSubtaskRepository.updateById(subtask);
+//
+//        //3.生成已卸货节点轨迹
+//        createEnteredWaybillOrderNode(param.getLng(), param.getLat(), waybillOrder, CarWaybillV1Enum.COMPLETION_LOADING);
+//        log.info("物流运单卸货成功!");
+//    }
+//
+//    /**
+//     * 更改物流订单状态
+//     * @param param
+//     * @param startTypeEnum
+//     * @param endTypeEnum
+//     */
+//    private KwtWaybillOrder updateWaybillOrderStayus(Long waybillOrderId, CarWaybillV1Enum startTypeEnum, CarWaybillV1Enum endTypeEnum) {
+//        KwtWaybillOrder waybillOrder = waybillOrderRepository.queryByBillOrderId(waybillOrderId);
+//        if (waybillOrder == null) {
+//            log.error("物流运单不存在,waybillOrderId:{}", waybillOrderId);
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_NOT_FOUND, "物流运单不存在!");
+//        }
+//
+//        if (startTypeEnum.getCode() != waybillOrder.getStatus()) {
+//            log.info("当前物流运单状态不正确,无法推进下一节点, waybillOrderId:{}", waybillOrderId);
+//            throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_STATUS_ERROR, "当前物流运单状态不正确,无法推进下一节点!");
+//        }
+//        //更改物流运单状态
+//        waybillOrder.setStatus(endTypeEnum.getCode());
+//        return waybillOrder;
+//    }
+//
+//    /**
+//     *  生成运单节点轨迹
+//     * @param param
+//     * @param waybillOrder
+//     */
+//    private void createEnteredWaybillOrderNode(String lng, String lat, KwtWaybillOrder waybillOrder, CarWaybillV1Enum carWaybillV1Enum) {
+//        log.info("创建车辆运单节点轨迹入参参数, wOrderId: {}", waybillOrder.getWOrderId());
+//        List<KwtWaybillOrderSubtask> waybillOrderSubtaskList = waybillOrderSubtaskRepository.queryByLogId(waybillOrder.getLOrderId());
+//        KwtWaybillOrderSubtask waybillOrderSubtask = Optional.ofNullable(waybillOrderSubtaskList)
+//                .stream()
+//                .flatMap(List::stream)
+//                .filter(Objects::nonNull)
+//                .findFirst()
+//                .orElseThrow(() -> new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_SUB_NOT_FOUND, "未找到有效的子运单"));
+//
+//        KwtWaybillOrderNode orderNode = new KwtWaybillOrderNode();
+//        orderNode.setWOrderId(waybillOrder.getId());
+//        orderNode.setWSubtaskId(waybillOrderSubtask.getWOrderId());
+//        orderNode.setOrderStatus(carWaybillV1Enum.getCode());
+//        orderNode.setTruckId(waybillOrder.getTruckId());
+//        orderNode.setTruckNo(waybillOrder.getTruckNo());
+//        orderNode.setDriverId(waybillOrder.getDriverId());
+//        orderNode.setDriverName(waybillOrder.getDriverName());
+//        orderNode.setLng(lng);
+//        orderNode.setLat(lat);
+//        waybillOrderNodeRepository.save(orderNode);
+//        log.info("创建车辆运单节点轨迹,节点轨迹ID:{}", orderNode.getId());
+//    }
+
+
+}

+ 19 - 0
sql/2025/mvp2/2025_11_03_donglang.sql

@@ -56,4 +56,23 @@ CREATE TABLE `kwf_driver_associated_track`
     PRIMARY KEY (`id`) USING BTREE
 ) COMMENT='司机关联车辆表(司机app)';
 
+create table kwt_waybill_order_node
+(
+    id                      bigint          NOT NULL AUTO_INCREMENT COMMENT '主键',
+    w_order_id              bigint          NOT NULL comment '车辆运单id',
+    w_subtask_id            bigint          NOT NULL comment '运单关联子单ID',
+    order_status            tinyint         NOT NULL comment '运单状态',
+    truck_id                bigint          NOT NULL comment '车辆id',
+    truck_no                varchar(11)     NULL comment '车牌号',
+    driver_id               bigint          NULL comment '司机id',
+    driver_name             varchar(11)     NULL comment '司机名称',
+    weighbridge_id          bigint          NULL comment '地磅id',
+    weighbridge_name        varchar(11)     NULL comment '地磅名称',
+    lng                     varchar(20)     NULL COMMENT '经度',
+    lat                     varchar(20)     NULL COMMENT '纬度',
+    create_by               bigint          NOT NULL default 0 comment '创建人',
+    create_time             datetime        NOT NULL default CURRENT_TIMESTAMP comment '创建时间',
+    PRIMARY KEY (`id`) USING BTREE
+) comment '车辆运单-节点轨迹';
+