|
|
@@ -3,6 +3,8 @@ package com.sckw.transport.task;
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.sckw.contract.api.RemoteContractService;
|
|
|
+import com.sckw.contract.api.feign.LogisticsScoreFeignService;
|
|
|
+import com.sckw.contract.api.model.dto.req.LogisticsScoreDetailFeignDto;
|
|
|
import com.sckw.core.common.enums.enums.ErrorCodeEnum;
|
|
|
import com.sckw.core.exception.BusinessException;
|
|
|
import com.sckw.core.exception.BusinessPlatfromException;
|
|
|
@@ -10,8 +12,9 @@ import com.sckw.core.model.enums.CarWaybillV1Enum;
|
|
|
import com.sckw.core.model.enums.LogisticsOrderV1Enum;
|
|
|
import com.sckw.core.utils.DateUtils;
|
|
|
import com.sckw.fleet.api.RemoteFleetService;
|
|
|
+import com.sckw.fleet.api.model.dto.RUpdateDriverScoreDto;
|
|
|
+import com.sckw.fleet.api.model.vo.DriverConductRulesVO;
|
|
|
import com.sckw.fleet.api.model.vo.TruckDispatchCoefficientVO;
|
|
|
-import com.sckw.transport.handler.CancelHandler;
|
|
|
import com.sckw.transport.model.*;
|
|
|
import com.sckw.transport.repository.*;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
@@ -19,6 +22,8 @@ import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
|
import org.apache.commons.collections4.MapUtils;
|
|
|
import org.apache.dubbo.config.annotation.DubboReference;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
@@ -42,17 +47,19 @@ public class LogisticsOrderCompletionTask {
|
|
|
private final KwtLogisticsOrderRepository logisticsOrderRepository;
|
|
|
private final KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
|
|
|
private final KwtWaybillOrderRepository waybillOrderRepository;
|
|
|
- private final KwtLogisticsOrderContractRepository logisticsOrderContractRepository;
|
|
|
private final KwtLogisticsOrderUnitRepository logisticsOrderUnitRepository;
|
|
|
+ private final KwtLogisticsOrderContractRepository logisticsOrderContractRepository;
|
|
|
private final KwtWaybillOrderNodeRepository waybillOrderNodeRepository;
|
|
|
|
|
|
@DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
|
|
|
- protected RemoteFleetService remoteFleetService;
|
|
|
+ private RemoteFleetService remoteFleetService;
|
|
|
|
|
|
@DubboReference(version = "1.0.0", group = "design", check = false)
|
|
|
private RemoteContractService remoteContractService;
|
|
|
|
|
|
- private final CancelHandler cancelHandler;
|
|
|
+ @Autowired
|
|
|
+ LogisticsScoreFeignService logisticsScoreFeignService;
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* 定时任务:每5分钟执行一次
|
|
|
@@ -160,10 +167,8 @@ public class LogisticsOrderCompletionTask {
|
|
|
* 可以根据实际需求调整执行频率
|
|
|
*/
|
|
|
@Scheduled(cron = "${schedule.waybill-order-completion-cron}")
|
|
|
- @Transactional(rollbackFor = Exception.class)
|
|
|
public void processWaybillOrder() {
|
|
|
log.info("超时取消运单定时任务开始...");
|
|
|
-
|
|
|
try {
|
|
|
// 查询状态为"已接单"的物流运单
|
|
|
List<KwtWaybillOrder> waybillOrderOrders = waybillOrderRepository.list(
|
|
|
@@ -183,37 +188,23 @@ public class LogisticsOrderCompletionTask {
|
|
|
//提取物流订单id
|
|
|
Set<Long> logisticOrderIds = waybillOrderOrders.stream().map(KwtWaybillOrder::getLOrderId).collect(Collectors.toSet());
|
|
|
|
|
|
- //物流订单和企业映射
|
|
|
- List<KwtLogisticsOrderUnit> logisticsOrderUnits = logisticsOrderUnitRepository.queryByLOrderIdsAndUnitType(logisticOrderIds, 2);
|
|
|
+ //物流订单和合同映射
|
|
|
+// List<KwtLogisticsOrderContract> logisticsOrderContracts = logisticsOrderContractRepository.queryByLogOrderIds(logisticOrderIds);
|
|
|
+// Map<Long, KwtLogisticsOrderContract> logisticsOrderAndContractMap = logisticsOrderContracts.stream()
|
|
|
+// .collect(Collectors.toMap(KwtLogisticsOrderContract::getLOrderId, Function.identity(), (x, y) -> x));
|
|
|
+//
|
|
|
+// Set<Long> contractIds = logisticsOrderContracts.stream().map(KwtLogisticsOrderContract::getContractId).collect(Collectors.toSet());
|
|
|
+// remoteContractService.queryContractUnitByContractId()
|
|
|
+
|
|
|
+ List<KwtLogisticsOrderUnit> logisticsOrderUnits = logisticsOrderUnitRepository.queryByLOrderIdsAndUnitType(logisticOrderIds, 1);
|
|
|
Map<Long, KwtLogisticsOrderUnit> logisticsOrderAndUnitMap = logisticsOrderUnits.stream()
|
|
|
.collect(Collectors.toMap(KwtLogisticsOrderUnit::getLOrderId, Function.identity(), (x, y) -> x));
|
|
|
if (MapUtils.isEmpty(logisticsOrderAndUnitMap)) {
|
|
|
throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "未找的物流订单和企业映射信息!");
|
|
|
}
|
|
|
|
|
|
- //过滤超时的运单
|
|
|
- List<KwtWaybillOrder> nearingCompletionOrders = new ArrayList<>();
|
|
|
-
|
|
|
- for (Map.Entry<Long, List<KwtWaybillOrder>> entry : waybillOrderAndLogOrderMap.entrySet()) {
|
|
|
- Long logisticOrderId = entry.getKey();
|
|
|
- //物流运单
|
|
|
- List<KwtWaybillOrder> waybillOrderList = entry.getValue();
|
|
|
- //供应商企业信息
|
|
|
- KwtLogisticsOrderUnit logisticsOrderUnit = logisticsOrderAndUnitMap.get(logisticOrderId);
|
|
|
- TruckDispatchCoefficientVO truckDispatchVO = remoteFleetService.findAutoTruckDispatchByEntId(logisticsOrderUnit.getEntId());
|
|
|
- if (truckDispatchVO == null) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- Integer driverTimeout = truckDispatchVO.getDriverTimeoutLimit();
|
|
|
-
|
|
|
- for (KwtWaybillOrder waybillOrder : waybillOrderList) {
|
|
|
- Long timeDiffMinutes = DateUtils.calculateTimeDiffMinutes(waybillOrder.getCreateTime(), new Date());
|
|
|
- if (timeDiffMinutes > driverTimeout.longValue()) {
|
|
|
- nearingCompletionOrders.add(waybillOrder);
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ // 过滤超时的运单
|
|
|
+ List<KwtWaybillOrder> nearingCompletionOrders = getKwtWaybillOrders(waybillOrderAndLogOrderMap, logisticsOrderAndUnitMap);
|
|
|
|
|
|
// 如果没有需要更新的物流运单,则直接返回
|
|
|
if (CollectionUtils.isEmpty(nearingCompletionOrders)){
|
|
|
@@ -225,20 +216,12 @@ public class LogisticsOrderCompletionTask {
|
|
|
for (KwtWaybillOrder waybillOrder : nearingCompletionOrders) {
|
|
|
try {
|
|
|
//执行取消运单
|
|
|
- processSingleWaybillOrder(waybillOrder);
|
|
|
+ processSingleWaybillOrder(waybillOrder, logisticsOrderAndUnitMap);
|
|
|
+ //异步处理
|
|
|
+ handleCancelActions(waybillOrder, logisticsOrderAndUnitMap);
|
|
|
successOrders.add(waybillOrder);
|
|
|
} catch (Exception e) {
|
|
|
- log.error("处理运单失败,ID: {}", waybillOrder.getId(), e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //事务提交后,批量解绑车辆
|
|
|
- for (KwtWaybillOrder order : successOrders) {
|
|
|
- try {
|
|
|
- remoteFleetService.unbindTruck(order.getEntId(), order.getDriverId());
|
|
|
- log.info("解绑车辆成功: 运单ID={}", order.getId());
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("解绑车辆失败,运单ID={}", order.getId(), e);
|
|
|
+ log.error("处理运单ID:{} 失败", waybillOrder.getId(), e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -249,24 +232,68 @@ public class LogisticsOrderCompletionTask {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 过滤超时的运单
|
|
|
+ * @param waybillOrderAndLogOrderMap
|
|
|
+ * @param logisticsOrderAndUnitMap
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<KwtWaybillOrder> getKwtWaybillOrders(Map<Long, List<KwtWaybillOrder>> waybillOrderAndLogOrderMap,
|
|
|
+ Map<Long, KwtLogisticsOrderUnit> logisticsOrderAndUnitMap) {
|
|
|
+ //过滤超时的运单
|
|
|
+ List<KwtWaybillOrder> nearingCompletionOrders = new ArrayList<>();
|
|
|
+
|
|
|
+ //供应商企业id
|
|
|
+ List<Long> entIds = logisticsOrderAndUnitMap.values().stream().map(KwtLogisticsOrderUnit::getEntId).distinct().collect(Collectors.toList());
|
|
|
+ //查询自动派车系数
|
|
|
+ List<TruckDispatchCoefficientVO> dispatchList = remoteFleetService.findAutoTruckDispatchByEntIds(entIds);
|
|
|
+ Map<Long, TruckDispatchCoefficientVO> entIdToDispatchMap = dispatchList.stream().collect(
|
|
|
+ Collectors.toMap(TruckDispatchCoefficientVO::getEntId, Function.identity()));
|
|
|
+
|
|
|
+ for (Map.Entry<Long, List<KwtWaybillOrder>> entry : waybillOrderAndLogOrderMap.entrySet()) {
|
|
|
+ Long logisticOrderId = entry.getKey();
|
|
|
+ //物流运单
|
|
|
+ List<KwtWaybillOrder> waybillOrderList = entry.getValue();
|
|
|
+ //供应商企业信息
|
|
|
+ KwtLogisticsOrderUnit unit = logisticsOrderAndUnitMap.get(logisticOrderId);
|
|
|
+ //自动派车系数
|
|
|
+ TruckDispatchCoefficientVO truckDispatchVO = entIdToDispatchMap.get(unit.getEntId());
|
|
|
+ if (truckDispatchVO == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ //司机超时限制分钟数
|
|
|
+ Integer driverTimeout = truckDispatchVO.getDriverTimeoutLimit();
|
|
|
+ for (KwtWaybillOrder waybillOrder : waybillOrderList) {
|
|
|
+ Long timeDiffMinutes = DateUtils.calculateTimeDiffMinutes(waybillOrder.getCreateTime(), new Date());
|
|
|
+ if (timeDiffMinutes > driverTimeout.longValue()) {
|
|
|
+ nearingCompletionOrders.add(waybillOrder);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nearingCompletionOrders;
|
|
|
+ }
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
- public void processSingleWaybillOrder(KwtWaybillOrder waybillOrder) {
|
|
|
- //1.获取子运单任务量
|
|
|
- KwtWaybillOrderSubtask subtask = waybillOrderSubtaskRepository.queryByWOrderId(waybillOrder.getId());
|
|
|
- if (subtask == null) {
|
|
|
- throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_SUB_NOT_FOUND, "未找到关联的子运单!");
|
|
|
- }
|
|
|
- BigDecimal entrustAmount = subtask.getEntrustAmount();
|
|
|
+ public void processSingleWaybillOrder(KwtWaybillOrder waybillOrder, Map<Long, KwtLogisticsOrderUnit> logisticsOrderAndUnitMap) {
|
|
|
+ try {
|
|
|
+ //1.获取子运单任务量
|
|
|
+ KwtWaybillOrderSubtask subtask = waybillOrderSubtaskRepository.queryByWOrderId(waybillOrder.getId());
|
|
|
+ if (subtask == null) {
|
|
|
+ throw new BusinessPlatfromException(ErrorCodeEnum.WAYBILL_ORDER_SUB_NOT_FOUND, "未找到关联的子运单!");
|
|
|
+ }
|
|
|
+ BigDecimal entrustAmount = subtask.getEntrustAmount();
|
|
|
|
|
|
- //2.更新上游订单:更新物流订单运输量
|
|
|
- updateLogOrder(waybillOrder, entrustAmount);
|
|
|
+ //2.更新上游订单:更新物流订单运输量
|
|
|
+ updateLogOrder(waybillOrder, entrustAmount);
|
|
|
|
|
|
- //3. 更新状态
|
|
|
- updateStatus(waybillOrder, subtask);
|
|
|
+ //3. 更新状态
|
|
|
+ updateStatus(waybillOrder, subtask);
|
|
|
|
|
|
- //4. 生成节点轨迹
|
|
|
- createNodeTrace(waybillOrder, subtask);
|
|
|
+ //4. 生成节点轨迹
|
|
|
+ createNodeTrace(waybillOrder, subtask);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw e; // 抛出异常,触发Seata全局回滚
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -322,4 +349,85 @@ public class LogisticsOrderCompletionTask {
|
|
|
}
|
|
|
|
|
|
|
|
|
+
|
|
|
+ @Async
|
|
|
+ public void handleCancelActions(KwtWaybillOrder waybillOrder, Map<Long, KwtLogisticsOrderUnit> logisticsOrderAndUnitMap) {
|
|
|
+ try {
|
|
|
+ unbindTruck(waybillOrder);
|
|
|
+ checkArrivedLoadingPointTimeout(waybillOrder, logisticsOrderAndUnitMap);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("异步处理取消后动作失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解绑车辆
|
|
|
+ * @param waybillOrder
|
|
|
+ */
|
|
|
+ private void unbindTruck(KwtWaybillOrder waybillOrder) {
|
|
|
+ remoteFleetService.unbindTruck(waybillOrder.getEntId(), waybillOrder.getDriverId());
|
|
|
+ log.info("解绑完成,解绑司机与车辆关系,运单id:{},企业id:{},司机id:{}", waybillOrder.getId(), waybillOrder.getEntId(), waybillOrder.getDriverId());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 司机超时到达装货点扣分
|
|
|
+ * @param waybillOrder
|
|
|
+ */
|
|
|
+ private void checkArrivedLoadingPointTimeout(KwtWaybillOrder waybillOrder, Map<Long, KwtLogisticsOrderUnit> logisticsOrderAndUnitMap) {
|
|
|
+ KwtLogisticsOrderUnit logisticsOrderUnit = logisticsOrderAndUnitMap.get(waybillOrder.getLOrderId());
|
|
|
+ //供应商id
|
|
|
+ Long supEntId = logisticsOrderUnit.getEntId();
|
|
|
+ DriverConductRulesVO driverRulesVO = remoteFleetService.findDriverConductRulesByEntId(logisticsOrderUnit.getEntId());
|
|
|
+ if (driverRulesVO == null) {
|
|
|
+ throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "未找到司机行为规则数据!");
|
|
|
+ }
|
|
|
+ Integer notOnTimeArrive = driverRulesVO.getNotOnTimeArriveScore();
|
|
|
+ if (notOnTimeArrive <= 0) {
|
|
|
+ log.warn("【司机未按时到场】司机扣分失败,企业{}的司机未按时到场分数配置异常,运单ID:{}", waybillOrder.getEntId(), waybillOrder.getId());
|
|
|
+ throw new BusinessPlatfromException(ErrorCodeEnum.DATA_NOT_EXIST, "【司机未按时到场】分数配置需大于0!");
|
|
|
+ }
|
|
|
+ //1、更新司机分数(减分)
|
|
|
+ notOnTimeArrive = -Math.abs(notOnTimeArrive);
|
|
|
+ updateDriverScore(supEntId, waybillOrder.getEntId(), waybillOrder.getDriverId(), notOnTimeArrive, "司机未按时到场(超时)");
|
|
|
+
|
|
|
+ //2、更新企业分数(减分)
|
|
|
+ updateLogEntScore(waybillOrder, supEntId, notOnTimeArrive, "司机未按时到场");
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改司机评分
|
|
|
+ * @param supeEntId
|
|
|
+ * @param entId
|
|
|
+ * @param driverId
|
|
|
+ * @param score
|
|
|
+ */
|
|
|
+ public void updateDriverScore(Long supeEntId, Long entId, Long driverId, Integer score, String action) {
|
|
|
+ RUpdateDriverScoreDto dto = new RUpdateDriverScoreDto();
|
|
|
+ dto.setSupEntId(supeEntId);
|
|
|
+ dto.setLogEntId(entId);
|
|
|
+ dto.setDriverId(driverId);
|
|
|
+ dto.setScore(BigDecimal.valueOf(score));
|
|
|
+ dto.setAction(action);
|
|
|
+
|
|
|
+ remoteFleetService.updateDriverScoreByEntId(dto);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新企业评分
|
|
|
+ * @param waybillOrder
|
|
|
+ * @param supplierId
|
|
|
+ * @param score
|
|
|
+ */
|
|
|
+ public void updateLogEntScore(KwtWaybillOrder waybillOrder, Long supplierId, Integer score, String remark) {
|
|
|
+ LogisticsScoreDetailFeignDto detailDto = new LogisticsScoreDetailFeignDto();
|
|
|
+ detailDto.setProviderEntId(supplierId);
|
|
|
+ detailDto.setLogisticsEntId(waybillOrder.getEntId());
|
|
|
+ detailDto.setInfluenceBy(waybillOrder.getDriverId());
|
|
|
+ detailDto.setAction(remark);
|
|
|
+ detailDto.setScoreChange(BigDecimal.valueOf(score));
|
|
|
+ logisticsScoreFeignService.updateLogisticsScore(detailDto);
|
|
|
+ }
|
|
|
+
|
|
|
}
|