liujie
2026-06-09 c96fbe6b0aeb413a17c429133ee6d81d138144b9
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -4,6 +4,7 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
@@ -33,6 +34,7 @@
import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto;
import com.xiaopeng.api.feignClient.account.SysGroupMenuClient;
import com.xiaopeng.api.feignClient.account.UserResourcesClient;
import com.xiaopeng.api.feignClient.account.XpAppUserClient;
import com.xiaopeng.api.feignClient.account.XpAppUserCollectAddrClient;
import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
@@ -48,6 +50,7 @@
import com.xiaopeng.api.feignClient.vehicleConvoy.*;
import com.xiaopeng.api.model.maintenance.XpTaskRule;
import com.xiaopeng.api.model.operation.*;
import com.xiaopeng.api.model.account.XpAppUser;
import com.xiaopeng.api.model.order.*;
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
@@ -87,6 +90,7 @@
import com.xiaopeng.common.redis.service.RedisService;
import com.xiaopeng.common.security.service.TokenService;
import com.xiaopeng.common.security.utils.SecurityUtils;
import com.xiaopeng.order.config.MinistryTransportProperties;
import com.xiaopeng.order.constant.I18nKeyConstant;
import com.xiaopeng.order.dto.MileageDto;
import com.xiaopeng.order.dto.UserOrderListDto;
@@ -98,6 +102,9 @@
import com.xiaopeng.order.mapper.XpCruiseOrderMapper;
import com.xiaopeng.order.mapper.XpOrderDetailMapper;
import com.xiaopeng.order.mapper.XpOrderMapper;
import com.xiaopeng.order.model.dto.CreditPaySuccessCallDto;
import com.xiaopeng.order.model.dto.RegulationOrderCreateInfoDTO;
import com.xiaopeng.order.model.dto.RegulationOrderMatchInfoDTO;
import com.xiaopeng.order.model.dto.XpOrderCommentDto;
import com.xiaopeng.order.model.dto.XpOrderPayDto;
import com.xiaopeng.order.model.query.XpHistoryOrderListQuery;
@@ -105,6 +112,7 @@
import com.xiaopeng.order.model.query.XpOrderPageQuery;
import com.xiaopeng.order.model.vo.*;
import com.xiaopeng.order.service.*;
import com.xiaopeng.order.utils.MinistryOfTransportOrderReporter;
import com.xiaopeng.order.utils.*;
import com.xiaopeng.order.utils.holiday.HolidayUtil;
import com.xiaopeng.order.vo.*;
@@ -161,10 +169,12 @@
    private final UserResourcesClient userResourcesClient;
    private final XpPointClient xpPointClient;
    private final XpVehicleClient xpVehicleClient;
    private final XpAppUserClient xpAppUserClient;
    private final XpAppUserCouponClient xpAppUserCouponClient;
    private final XpFleetClient xpFleetClient;
    private final XpFleetVehicleClient xpFleetVehicleClient;
    private final UserVehicleClient userVehicleClient;
    private final MinistryTransportProperties ministryTransportProperties;
    @Lazy
    @Autowired
    private IXpOrderEvaluateService xpOrderEvaluateService;
@@ -189,6 +199,7 @@
    @Autowired
    private IXpTestOrderService xpTestOrderService;
    private final XpMapClient xpMapClient;
    private final MinistryOfTransportOrderReporter ministryOfTransportOrderReporter;
    @Resource
    private XpRoutePlanClient xpRoutePlanClient;
    @Resource
@@ -224,6 +235,9 @@
    @Resource
    private XpFrdXfipEventClient xpFrdXfipEventClient;
    @Resource
    private XpTargetedServiceClient targetedServiceClient;
    @Value("${robotaxi.appId:xp_robotaxi_api}")
    private String appid;
@@ -516,7 +530,6 @@
        if (Objects.nonNull(query.getEndTime())) {
            wrapper.le(XpOrder::getCreateTime, LocalDateTime.of(query.getEndTime(), LocalTime.MAX));
        }
        wrapper.orderByDesc(XpOrder::getCreateTime);
        return wrapper;
    }
@@ -701,7 +714,9 @@
     * 取消订单
     */
    private void cancelOrder(XpOrder order) {
        if(StringUtils.isNotEmpty(order.getQueueName())){
        redisService.removeByPattern(order.getQueueName(), order.getOrderNumber());
        }
        Long userId = order.getAppUserId();
        Integer status = order.getStatus();
@@ -861,6 +876,7 @@
                // 下发命令
                PushOrderDto pushOrderDto = new PushOrderDto();
                pushOrderDto.setEndTaskId(order.getStatus() < 6 ? order.getXpuStartTaskId() : order.getXpuEndTaskId());
                pushOrderDto.setOrderId(order.getId().toString());
                pushOrderDto.setVin(xpVehicle.getVehicleVin());
                pushOrderDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
@@ -1011,6 +1027,17 @@
        }
        if (order.getOfficialPartnerId() == null) {
            //给车端发送取消靠边停车的报文
            PushOrderDto cancelDto = new PushOrderDto();
            cancelDto.setStartTaskId(order.getXpuStartTaskId());
            cancelDto.setEndTaskId(order.getXpuEndTaskId());
            cancelDto.setOrderId(order.getId().toString());
            cancelDto.setVin(vin);
            cancelDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
            cancelDto.setCancelScene(CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE.getCode());
            orderMissionClient.cancelOrder(cancelDto);
            //创建定时任务执行延迟驶离终点和下发巡游单
            XpPoint point = xpPointClient.queryById(order.getEndPointId()).getData();
            Integer parkingTimeLimit = point.getParkingTimeLimit();
@@ -1352,7 +1379,11 @@
                returnOrder.setOrderReverse(lastCruise.getOrderReverse());
                log.info("巡游订单状态为{},默认返回原出发点", lastCruise.getStatus());
            }
            R<XpCruiseOrder> orderR = xpCruisePlanClient.findReturnCruisePoint(returnOrder);
            if(null != orderR && 200 != orderR.getCode()){
                log.error(orderR.getMsg());
                return;
            }
            xpCruiseOrderMapper.insert(returnOrder);
            // 下发巡游订单到原车辆
@@ -1880,7 +1911,9 @@
            throw new ServiceException("订单状态错误", I18nKeyConstant.ORDER_STATUS_ERROR);
        }
        try {
            if(StringUtils.isNotEmpty(order.getQueueName())){
            redisService.removeByPattern(order.getQueueName(), order.getOrderNumber());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
@@ -1973,6 +2006,39 @@
                    e.printStackTrace();
                }
                //判断是否有连环单
                String json = redisService.getCacheObject(CacheConstants.nextOrder(order.getId().toString()));
                if (StringUtils.isNotEmpty(json)) {
                    JSONObject jsonObject = JSON.parseObject(json);
                    Long id = jsonObject.getLong("orderId");
                    //判断订单状态
                    XpOrder xpOrder1 = this.getById(id);
                    if (2 == xpOrder1.getStatus()) {
                        //开始推送订单给车端
                        // 下发命令
                        PushOrderDto pushOrderDto = new PushOrderDto();
                        pushOrderDto.setStartTaskId(xpOrder1.getXpuStartTaskId());
                        pushOrderDto.setEndTaskId(xpOrder1.getXpuEndTaskId());
                        pushOrderDto.setVin(vin);
                        pushOrderDto.setOrderId(xpOrder1.getId().toString());
                        pushOrderDto.setStartWaypointId(xpOrder1.getStartPointId());
                        pushOrderDto.setEndWaypointId(xpOrder1.getEndPointId());
                        pushOrderDto.setStartLatitude(xpOrder1.getStartLat());
                        pushOrderDto.setStartLongitude(xpOrder1.getStartLon());
                        pushOrderDto.setEndLatitude(xpOrder1.getEndLat());
                        pushOrderDto.setEndLongitude(xpOrder1.getEndLon());
                        pushOrderDto.setEndPoiName(xpOrder1.getEndPointName());
                        pushOrderDto.setOrderType(OrderType.USER_ORDER);
                        pushOrderDto.setStage(1);
                        pushOrderDto.setLastOrderId(order.getId().toString());
                        pushOrderDto.setLastXpuTaskId(status == 1 ? order.getXpuStartTaskId() : order.getXpuEndTaskId());
                        pushOrderDto.setTaskActionType(TaskActionType.kTerminateForNewTask);
                        // 调用推送服务  orderId + carVin
                        orderMissionClient.pushOrder(pushOrderDto);
                        log.info("开始推送 {} 订单到XPU。单号 {}", xpOrder1.getOrderNumber(), xpOrder1.getOrderNumber());
                        return;
                    }
                }
                //车辆继续巡游
                addCruiseMission(order, status);
            }
@@ -2027,7 +2093,9 @@
        xpOrderCancel.setCreateTime(LocalDateTime.now());
        xpOrderCancelService.save(xpOrderCancel);
        if(StringUtils.isNotEmpty(order.getQueueName())){
        redisService.removeByPattern(order.getQueueName(), order.getOrderNumber());
        }
        // 消息推送
        Map<String, Object> params = new HashMap<>();
@@ -2555,7 +2623,7 @@
            log.info("计算价格-保存费用明细 {} {}", orderId, JSON.toJSONString(xpOrderDetails));
            // 默认费率1
            double priceRate = 1;
            double priceRate = 100;
            if (pricing.getIsDynamicPrice() == 1) {
                // 先判断是否已经调价过了
                Object userDynamicPriceObj = redisService.getCacheObject("USER_DYNAMIC_PRICE_" + order.getCityId() + "_" + uid);
@@ -2563,13 +2631,9 @@
                    // 是否调价过了
                    priceRate = Double.parseDouble(userDynamicPriceObj.toString());
                } else {
                    //是否触发动态调价 redis获取
                    Object dynamicPriceObj = redisService.getCacheObject("DYNAMIC_PRICE_" + order.getCityId());
                    if (dynamicPriceObj != null) {
                        JSONObject jsonObject = JSONObject.parseObject(pricing.getDynamicPricingJson());
                        // 触发动态调价
                        // value=时间
                        String timeStr = dynamicPriceObj.toString();
                    Integer num1 = jsonObject.getInteger("num1");
                    String timeStr = LocalDateTime.now().minusMinutes(num1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                        // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率
                        Integer num = this.getOrderNum(new GetOrderNumDto(timeStr, order.getCityId()));
                        // X单上升一次调价
@@ -2592,11 +2656,9 @@
                            }
                        }
                    }
                }
                log.info("供需后的费率 {}", priceRate);
                //是否触发动态调价 redis获取
                Object dynamicPriceObj = redisService.getCacheObject("DYNAMIC_PRICE_" + order.getCityId());
                if (dynamicPriceObj != null) {
                    JSONObject jsonObject = JSONObject.parseObject(pricing.getDynamicPricingJson());
                    // 天气预报动态调价
                    JSONArray ws = jsonObject.getJSONArray("weatherRules");
@@ -2616,7 +2678,8 @@
                        }
                    }
                }
            }
            priceRate = new BigDecimal(priceRate).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
            log.info("浮动费率 {}", priceRate);
            log.info("计算价格-计算费率 {} {}", orderId, priceRate);
            order.setOrderMoney(totalPrice.multiply(new BigDecimal(priceRate)));
            order.setAppUserId(null);
@@ -2684,7 +2747,7 @@
            log.info("应付总额: " + totalAmount + " 元");
            BigDecimal startMoney = BigDecimal.ZERO;
            // 默认费率1
            double priceRate = 1;
            double priceRate = 100;
            if (pricing.getIsDynamicPrice() == 1) {
                // 先判断是否已经调价过了
                Object userDynamicPriceObj = redisService.getCacheObject("USER_DYNAMIC_PRICE_" + order.getCityId() + "_" + uid);
@@ -2692,13 +2755,9 @@
                    // 是否调价过了
                    priceRate = Double.parseDouble(userDynamicPriceObj.toString());
                } else {
                    //是否触发动态调价 redis获取
                    Object dynamicPriceObj = redisService.getCacheObject("DYNAMIC_PRICE_" + order.getCityId());
                    if (dynamicPriceObj != null) {
                        JSONObject jsonObject = JSONObject.parseObject(pricing.getDynamicPricingJson());
                        // 触发动态调价
                        // value=时间
                        String timeStr = dynamicPriceObj.toString();
                    Integer num1 = jsonObject.getInteger("num1");
                    String timeStr = LocalDateTime.now().minusMinutes(num1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                        // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率
                        Integer num = this.getOrderNum(new GetOrderNumDto(timeStr, order.getCityId()));
                        // X单上升一次调价
@@ -2721,11 +2780,9 @@
                            }
                        }
                    }
                }
                log.info("供需后的费率 {}", priceRate);
                //是否触发动态调价 redis获取
                Object dynamicPriceObj = redisService.getCacheObject("DYNAMIC_PRICE_" + order.getCityId());
                if (dynamicPriceObj != null) {
                    JSONObject jsonObject = JSONObject.parseObject(pricing.getDynamicPricingJson());
                    // 天气预报动态调价
                    JSONArray ws = jsonObject.getJSONArray("weatherRules");
@@ -2745,7 +2802,8 @@
                        }
                    }
                }
            }
            priceRate = new BigDecimal(priceRate).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
            log.info("浮动费率 {}", priceRate);
            log.info("计算价格-计算费率 {} {}", orderId, priceRate);
            // 封装费用明细数据
            for (Map.Entry<String, BigDecimal> stringBigDecimalEntry : bill.entrySet()) {
@@ -2965,8 +3023,23 @@
        // 判断是否有计划
        R<XpCruisePlanVehicle> xpCruisePlanR = xpCruisePlanClient.getCruisePlan(vehicle.getId());
        if (xpCruisePlanR == null || xpCruisePlanR.getData() == null) {
            log.info("添加巡游单失败,没有符合条件的巡游计划", vehicle.getPlateNumber());
            log.info("未找到匹配的巡游计划,无法执行巡游订单 {}", vehicle.getPlateNumber());
            //没有巡游计划,判断是否在定向服务里面
            List<XpTargetedServiceVehicle> data = targetedServiceClient.getAllTargetedServiceVehicleByCityCode(order.getCityCode()).getData();
            if(data.isEmpty()){
                log.info("给车端发送取消行程报文 {}", vehicle.getPlateNumber());
                PushOrderDto cancelDto = new PushOrderDto();
                cancelDto.setStartTaskId(order.getXpuStartTaskId());
                cancelDto.setEndTaskId(order.getXpuEndTaskId());
                cancelDto.setOrderId(order.getId().toString());
                String vin1 = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
                cancelDto.setVin(vin1);
                cancelDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
                cancelDto.setCancelScene(CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE.getCode());
                orderMissionClient.cancelOrder(cancelDto);
            return;
            }
        }
        // 获取配置 根据配置判断是否该收车 如果是则找到收车点位进行收车操作
        R<XpTaskRule> xpTaskRuleR = xpTaskRuleClient.queryDetail();
@@ -3013,11 +3086,14 @@
            xpCruiseOrder.setLastOrderId(xpCruiseOrders.getId());
            xpCruiseOrder.setMissionId(xpCruiseOrders.getMissionId());
        }
        // 先找计划
        R<List<XpCruisePlanPoint>> pointList = xpCruisePlanClient.getCruisePlanPointList(vehicle.getId());
        if(200 != pointList.getCode()){
            return;
        }
        //所有没有赋值终点点位的情况,全部导航到巡游计划的第一个点位开始执行巡游任务
        if (null == xpCruiseOrder.getEndPointId()) {
            // 先找计划
            List<XpCruisePlanPoint> planPointList = xpCruisePlanClient.getCruisePlanPointList(vehicle.getId()).getData();
            XpCruisePlanPoint xpCruisePlanPoint = planPointList.get(0);
            XpCruisePlanPoint xpCruisePlanPoint = pointList.getData().get(0);
            Long endPointId = xpCruisePlanPoint.getPointId();
            XpPoint endPoint = xpPointClient.queryById(endPointId).getData();
            xpCruiseOrder.setEndPointId(endPointId);
@@ -3040,11 +3116,69 @@
                xpVehicleClient.updateVehicleById(vehicle1);
                //找到车辆的收车点位 更新终点点位
                R<XpCruiseOrder> returnCruisePoint = xpCruisePlanClient.findReturnCruisePoint(xpCruiseOrder);
                if (200 != returnCruisePoint.getCode()) {
                if (200 == returnCruisePoint.getCode()) {
                    xpCruiseOrder = returnCruisePoint.getData();
                    xpCruiseOrder.setOrderType(2);
                    xpCruiseOrder.setOrderReverse(1);
                }
            }
        }else{
            //获取巡游导航数据,如果无法获取到有效的导航,则继续用下一个点位作为终点
            LonLatDto destination = new LonLatDto();
            LonLatDto origin = new LonLatDto();
            boolean ROUTE_FLAG = false;
            boolean start = false;
            if(xpCruiseOrder.getOrderReverse() == 1){
                for (XpCruisePlanPoint xpCruisePlanPoint1 : pointList.getData()) {
                    if (start || xpCruisePlanPoint1.getPointId().equals(xpCruiseOrder.getEndPointId())) {
                        start = true;
                        origin.setLongitude(xpCruiseOrder.getStartLon());
                        origin.setLatitude(xpCruiseOrder.getStartLat());
                        XpPoint xpPoint1 = xpPointClient.queryById(xpCruisePlanPoint1.getPointId()).getData();
                        destination.setLongitude(xpPoint1.getPointLon());
                        destination.setLatitude(xpPoint1.getPointLat());
                        OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto();
                        dto1.setOrigin(origin);
                        dto1.setDestination(destination);
                        dto1.setRouteType(3);
                        R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1);
                        if (200 != routeVoR.getCode()) {
                            continue;
                        }
                        RouteVo routeVo = routeVoR.getData();
                        redisService.setCacheObject("CRUISE_ROUTE:" + xpCruiseOrder.getVehicleId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS);
                        ROUTE_FLAG = true;
                        break;
                    }
                }
            }else{
                for (int i = pointList.getData().size() - 1; i >= 0; i--) {
                    XpCruisePlanPoint xpCruisePlanPoint1 = pointList.getData().get(i);
                    if(start || xpCruisePlanPoint1.getPointId().equals(xpCruiseOrder.getEndPointId())){
                        start = true;
                        origin.setLongitude(xpCruiseOrder.getStartLon());
                        origin.setLatitude(xpCruiseOrder.getStartLat());
                        XpPoint xpPoint1 = xpPointClient.queryById(xpCruisePlanPoint1.getPointId()).getData();
                        destination.setLongitude(xpPoint1.getPointLon());
                        destination.setLatitude(xpPoint1.getPointLat());
                        OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto();
                        dto1.setOrigin(origin);
                        dto1.setDestination(destination);
                        dto1.setRouteType(3);
                        R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1);
                        if (200 != routeVoR.getCode()) {
                            continue;
                        }
                        RouteVo routeVo = routeVoR.getData();
                        redisService.setCacheObject("CRUISE_ROUTE:" + xpCruiseOrder.getVehicleId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS);
                        ROUTE_FLAG = true;
                        break;
                    }
                }
            }
            if(!ROUTE_FLAG){
                log.info("巡游计划获取导航信息失败 {}", JSON.toJSONString(vehicle));
                return;
            }
        }
        xpCruiseOrderMapper.insert(xpCruiseOrder);
@@ -3084,6 +3218,9 @@
        R<XpCruisePlanVehicle> xpCruisePlanR = xpCruisePlanClient.getCruisePlan(vehicle.getId());
        if (xpCruisePlanR == null || xpCruisePlanR.getData() == null) {
            log.info("未找到匹配的巡游计划,无法执行巡游订单 {}", vehicle.getPlateNumber());
            //没有巡游计划,判断是否在定向服务里面
            List<XpTargetedServiceVehicle> data = targetedServiceClient.getAllTargetedServiceVehicleByCityCode(order.getCityCode()).getData();
            if(data.isEmpty()){
            log.info("给车端发送取消行程报文 {}", vehicle.getPlateNumber());
            PushOrderDto cancelDto = new PushOrderDto();
@@ -3096,6 +3233,7 @@
            cancelDto.setCancelScene(CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE.getCode());
            orderMissionClient.cancelOrder(cancelDto);
            return;
            }
        }
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class);
@@ -3144,10 +3282,14 @@
            xpCruiseOrder.setLastOrderId(xpCruiseOrders.getId());
            xpCruiseOrder.setMissionId(xpCruiseOrders.getMissionId());
        }
        // 先找计划
        R<List<XpCruisePlanPoint>> pointList = xpCruisePlanClient.getCruisePlanPointList(vehicle.getId());
        if(200 != pointList.getCode()){
            return;
        }
        //所有没有赋值终点点位的情况,全部导航到巡游计划的第一个点位开始执行巡游任务
        if (null == xpCruiseOrder.getEndPointId()) {
            // 先找计划
            List<XpCruisePlanPoint> planPointList = xpCruisePlanClient.getCruisePlanPointList(vehicle.getId()).getData();
            List<XpCruisePlanPoint> planPointList = pointList.getData();
            XpCruisePlanPoint xpCruisePlanPoint = planPointList.get(0);
            Long endPointId = xpCruisePlanPoint.getPointId();
            XpPoint endPoint = xpPointClient.queryById(endPointId).getData();
@@ -3178,6 +3320,64 @@
                    xpCruiseOrder.setOrderType(2);
                    xpCruiseOrder.setOrderReverse(1);
                }
            }
        }else{
            //获取巡游导航数据,如果无法获取到有效的导航,则继续用下一个点位作为终点
            LonLatDto destination = new LonLatDto();
            LonLatDto origin = new LonLatDto();
            boolean ROUTE_FLAG = false;
            boolean start = false;
            if(xpCruiseOrder.getOrderReverse() == 1){
                for (XpCruisePlanPoint xpCruisePlanPoint1 : pointList.getData()) {
                    if (start || xpCruisePlanPoint1.getPointId().equals(xpCruiseOrder.getEndPointId())) {
                        start = true;
                        origin.setLongitude(xpCruiseOrder.getStartLon());
                        origin.setLatitude(xpCruiseOrder.getStartLat());
                        XpPoint xpPoint1 = xpPointClient.queryById(xpCruisePlanPoint1.getPointId()).getData();
                        destination.setLongitude(xpPoint1.getPointLon());
                        destination.setLatitude(xpPoint1.getPointLat());
                        OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto();
                        dto1.setOrigin(origin);
                        dto1.setDestination(destination);
                        dto1.setRouteType(3);
                        R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1);
                        if (200 != routeVoR.getCode()) {
                            continue;
                        }
                        RouteVo routeVo = routeVoR.getData();
                        redisService.setCacheObject("CRUISE_ROUTE:" + xpCruiseOrder.getVehicleId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS);
                        ROUTE_FLAG = true;
                        break;
                    }
                }
            }else{
                for (int i = pointList.getData().size() - 1; i >= 0; i--) {
                    XpCruisePlanPoint xpCruisePlanPoint1 = pointList.getData().get(i);
                    if(start || xpCruisePlanPoint1.getPointId().equals(xpCruiseOrder.getEndPointId())){
                        start = true;
                        origin.setLongitude(xpCruiseOrder.getStartLon());
                        origin.setLatitude(xpCruiseOrder.getStartLat());
                        XpPoint xpPoint1 = xpPointClient.queryById(xpCruisePlanPoint1.getPointId()).getData();
                        destination.setLongitude(xpPoint1.getPointLon());
                        destination.setLatitude(xpPoint1.getPointLat());
                        OrderRouteAndFareDto dto1 = new OrderRouteAndFareDto();
                        dto1.setOrigin(origin);
                        dto1.setDestination(destination);
                        dto1.setRouteType(3);
                        R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto1);
                        if (200 != routeVoR.getCode()) {
                            continue;
                        }
                        RouteVo routeVo = routeVoR.getData();
                        redisService.setCacheObject("CRUISE_ROUTE:" + xpCruiseOrder.getVehicleId(), com.alibaba.fastjson.JSON.toJSONString(routeVo), 24L, TimeUnit.DAYS);
                        ROUTE_FLAG = true;
                        break;
                    }
                }
            }
            if(!ROUTE_FLAG){
                log.info("巡游计划获取导航信息失败 {}", JSON.toJSONString(vehicle));
                return;
            }
        }
@@ -3604,6 +3804,7 @@
        if (insert <= 0) {
            return false;
        }
//        pushOrderCreateToMinistry(xpOrder, "新增订单");
        return true;
    }
@@ -3876,7 +4077,9 @@
                // Redis弹出这个队列元素
                // value 订单Id_经纬度_状态_用户id_订单编号_距离_时间
                try {
                    redisService.popFirstElement(order.getQueueName());
                    if(StringUtils.isNotEmpty(order.getQueueName())){
                        redisService.removeByPattern(order.getQueueName(), order.getOrderNumber());
                    }
                } catch (Exception e) {
                    log.error("Redis弹出队列元素出错");
                }
@@ -3895,6 +4098,9 @@
                this.updateById(order);
                order.setAppUserId(appUserId);
                bootCommonService.setCache_orderStatus(order.getId(), order, null);
                if (vehicle != null) {
//                    pushOrderMatchToMinistry(order, vehicle, appUserId, order.getAcceptanceTime(), "推单成功");
                }
                //构建推送消息
                Map<String, Object> params = new HashMap<>();
@@ -4550,6 +4756,8 @@
        if (xpOrder.getStatus() >= 8) {
            return R.fail("订单已结束,无法修改");
        }
        XpVehicle matchedVehicle = null;
        LocalDateTime distributeTime = null;
        switch (vo.getOrderStatus()) {
            case 2:
@@ -4566,13 +4774,17 @@
                if (null == xpVehicle) {
                    return R.fail("车牌号不存在");
                }
                matchedVehicle = xpVehicle;
                xpOrder.setOfficialPartnerId(officialPartnerId);
                xpOrder.setVehicleId(xpVehicle.getId());
                xpOrder.setAcceptanceTime(vo.getAcceptanceTime());
                distributeTime = vo.getAcceptanceTime();
                redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), OrderStatusEnum.READY_DEPART.getCode(), 24L, TimeUnit.HOURS);
                //将订单弹出队列
                try {
                    redisService.popFirstElement(xpOrder.getQueueName());
                    if(StringUtils.isNotEmpty(xpOrder.getQueueName())){
                        redisService.removeByPattern(xpOrder.getQueueName(), xpOrder.getOrderNumber());
                    }
                } catch (Exception e) {
                    log.error("Redis弹出队列元素出错");
                }
@@ -4856,6 +5068,9 @@
        }
        xpOrder.setStatus(vo.getOrderStatus());
        this.updateById(xpOrder);
        if (vo.getOrderStatus() == 2 && matchedVehicle != null) {
//            pushOrderMatchToMinistry(xpOrder, matchedVehicle, xpOrder.getAppUserId(), distributeTime, "合作商接单成功");
        }
        //推送订单状态给乘客端
        Map<String, Object> params = new HashMap<>();
        Map<String, Object> content = new HashMap<>();
@@ -4891,6 +5106,185 @@
        return R.ok();
    }
    private void pushOrderCreateToMinistry(XpOrder order, String scene) {
        if (order == null) {
            return;
        }
        try {
            RegulationOrderCreateInfoDTO dto = buildOrderCreateInfoForMinistry(order);
            String response = ministryOfTransportOrderReporter.pushOrderCreateInfo(dto);
            log.info("{}后上报交通部DDFQ完成, orderId={}, orderNo={}, response={}",
                    scene, order.getId(), order.getOrderNumber(), response);
        } catch (Exception e) {
            log.error("{}后上报交通部DDFQ失败, orderId={}, orderNo={}",
                    scene, order.getId(), order.getOrderNumber(), e);
        }
    }
    private void pushOrderMatchToMinistry(XpOrder order, XpVehicle vehicle, Long appUserId, LocalDateTime distributeTime, String scene) {
        if (order == null || vehicle == null) {
            return;
        }
        try {
            RegulationOrderMatchInfoDTO dto = buildOrderMatchInfoForMinistry(order, vehicle, appUserId, distributeTime);
            String response = ministryOfTransportOrderReporter.pushOrderMatchInfo(dto);
            log.info("{}后上报交通部DDCG完成, orderId={}, orderNo={}, vehicleId={}, response={}",
                    scene, order.getId(), order.getOrderNumber(), vehicle.getId(), response);
        } catch (Exception e) {
            log.error("{}后上报交通部DDCG失败, orderId={}, orderNo={}, vehicleId={}",
                    scene, order.getId(), order.getOrderNumber(), vehicle.getId(), e);
        }
    }
    private RegulationOrderCreateInfoDTO buildOrderCreateInfoForMinistry(XpOrder order) {
        XpAppUser appUser = queryAppUser(order.getAppUserId());
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime orderTime = defaultIfNull(order.getCreateTime(), now);
        LocalDateTime departTime = order.getEstimatedTime() != null
                ? order.getEstimatedTime()
                : defaultIfNull(order.getRideTime(), orderTime);
        RegulationOrderCreateInfoDTO dto = new RegulationOrderCreateInfoDTO();
        dto.setCompanyId(ministryTransportProperties.getCompanyId());
        dto.setAddress(ministryTransportProperties.getAddressCode());
        dto.setOrderId(defaultIfBlank(order.getOrderNumber(), String.valueOf(order.getId())));
        dto.setDepartTime(formatTransportTime(departTime));
        dto.setOrderTime(formatTransportTime(orderTime));
        dto.setPassengerPhone(appUser == null ? "" : defaultIfBlank(appUser.getPhoneNumber(), ""));
        dto.setPassengerNote("");
        dto.setDeparture(defaultIfBlank(order.getStartAddress(), ""));
        dto.setDepLongitude(formatCoordinate(order.getStartLon()));
        dto.setDepLatitude(formatCoordinate(order.getStartLat()));
        dto.setDestination(defaultIfBlank(order.getEndAddress(), ""));
        dto.setDestLongitude(formatCoordinate(order.getEndLon()));
        dto.setDestLatitude(formatCoordinate(order.getEndLat()));
        dto.setEncrypt("1");
        dto.setFareType(ministryTransportProperties.getFareType());
        dto.setOrderSource("0");
        dto.setPsgName(appUser == null ? "乘客" : defaultIfBlank(appUser.getNickName(), "乘客"));
        dto.setPsgGender(mapPassengerGender(appUser == null ? null : appUser.getGender()));
        dto.setPsgTotal("1");
        dto.setIsReserve(order.getEstimatedTime() != null ? "1" : "0");
        dto.setPreMile(formatDecimal(order.getMileageKilometers(), 0));
        dto.setPreTime(formatDecimal(order.getDuration(), 0));
        dto.setPreFare(formatAmount(order.getOrderMoney()));
        dto.setDepartCity(defaultIfBlank(order.getCityCode(), ministryTransportProperties.getDepartCityDefault()));
        dto.setDestCity(defaultIfBlank(order.getCityCode(), ministryTransportProperties.getDestCityDefault()));
        dto.setIsFromThirdPlatform("0");
        dto.setProtocolVersion(ministryTransportProperties.getProtocolVersion());
        return dto;
    }
    private RegulationOrderMatchInfoDTO buildOrderMatchInfoForMinistry(XpOrder order, XpVehicle vehicle, Long appUserId, LocalDateTime distributeTime) {
        String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vin)), VehiclePosition.class);
        GeoJsonPoint point = vehiclePosition == null ? null : vehiclePosition.getPoint();
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime orderTime = defaultIfNull(order.getCreateTime(), now);
        LocalDateTime actualDistributeTime = defaultIfNull(distributeTime, defaultIfNull(order.getAcceptanceTime(), now));
        RegulationOrderMatchInfoDTO dto = new RegulationOrderMatchInfoDTO();
        dto.setCompanyId(ministryTransportProperties.getCompanyId());
        dto.setAddress(ministryTransportProperties.getAddressCode());
        dto.setOrderId(defaultIfBlank(order.getOrderNumber(), String.valueOf(order.getId())));
        dto.setLongitude(formatCoordinate(point == null ? order.getStartLon() : point.getX()));
        dto.setLatitude(formatCoordinate(point == null ? order.getStartLat() : point.getY()));
        dto.setEncrypt("1");
        dto.setLicenseId(ministryTransportProperties.getDriverLicenseId());
        dto.setDriverPhone(ministryTransportProperties.getDriverPhone());
        dto.setVehicleNo(defaultIfBlank(vehicle.getPlateNumber(), ""));
        dto.setPlateColor(getPlateColor(vehicle.getPlateNumber()));
        dto.setDistributeTime(formatTransportTime(actualDistributeTime));
        dto.setOrderTime(formatTransportTime(orderTime));
        dto.setCarCertNo(ministryTransportProperties.getVehicleCertNo());
        dto.setDriverName(ministryTransportProperties.getDriverName());
        dto.setIdNo(ministryTransportProperties.getDriverIdNo());
        dto.setDriCertNo(ministryTransportProperties.getDriverCertNo());
        dto.setDepartCity(defaultIfBlank(order.getCityCode(), ministryTransportProperties.getDepartCityDefault()));
        dto.setDestCity(defaultIfBlank(order.getCityCode(), ministryTransportProperties.getDestCityDefault()));
        dto.setDepartLocale(defaultIfBlank(order.getStartAddress(), ""));
        dto.setDepartLocaleDetail(defaultIfBlank(order.getStartAddress(), ""));
        dto.setDepartLon(formatCoordinate(order.getStartLon()));
        dto.setDepartLat(formatCoordinate(order.getStartLat()));
        dto.setDesLocale(defaultIfBlank(order.getEndAddress(), ""));
        dto.setDesLocaleDetail(defaultIfBlank(order.getEndAddress(), ""));
        dto.setDesLon(formatCoordinate(order.getEndLon()));
        dto.setDesLat(formatCoordinate(order.getEndLat()));
        dto.setLatestDestTime(formatTransportTime(actualDistributeTime.minusMinutes(30)));
        dto.setIsFromThirdPlatform("0");
        dto.setProtocolVersion(ministryTransportProperties.getProtocolVersion());
        return dto;
    }
    private XpAppUser queryAppUser(Long appUserId) {
        if (appUserId == null) {
            return null;
        }
        try {
            R<XpAppUser> result = xpAppUserClient.queryOperationsUserById(appUserId);
            return result == null ? null : result.getData();
        } catch (Exception e) {
            log.warn("查询乘客信息失败, appUserId={}", appUserId, e);
            return null;
        }
    }
    private LocalDateTime defaultIfNull(LocalDateTime value, LocalDateTime defaultValue) {
        return value == null ? defaultValue : value;
    }
    private String defaultIfBlank(String value, String defaultValue) {
        return StringUtils.isBlank(value) ? defaultValue : value;
    }
    private String formatTransportTime(LocalDateTime time) {
        return time == null ? null : time.format(MinistryOfTransportOrderReporter.DATA_TIME_FORMATTER);
    }
    private String formatCoordinate(Double value) {
        if (value == null) {
            return "0";
        }
        return BigDecimal.valueOf(value)
                .multiply(BigDecimal.valueOf(1_000_000L))
                .setScale(0, RoundingMode.HALF_UP)
                .toPlainString();
    }
    private String formatDecimal(Number value, int scale) {
        if (value == null) {
            return "0";
        }
        return BigDecimal.valueOf(value.doubleValue())
                .setScale(scale, RoundingMode.HALF_UP)
                .toPlainString();
    }
    private String formatAmount(BigDecimal value) {
        if (value == null) {
            return "0";
        }
        return value.stripTrailingZeros().toPlainString();
    }
    private String mapPassengerGender(Integer gender) {
        if (Integer.valueOf(1).equals(gender)) {
            return "1";
        }
        if (Integer.valueOf(2).equals(gender)) {
            return "2";
        }
        return "0";
    }
    private String getPlateColor(String plateNumber) {
        if (StringUtils.isBlank(plateNumber)) {
            return "蓝色";
        }
        String plateWithoutProvince = plateNumber.substring(1);
        return plateWithoutProvince.length() == 7 ? "渐变绿" : "蓝色";
    }
    @Override
@@ -5127,6 +5521,27 @@
        updateById(order);
    }
    @Override
    public CreditPayCallVo creditPaySuccessCall(CreditPaySuccessCallDto dto) {
        LambdaQueryWrapper<XpOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(XpOrder::getAuthOrderId, dto.getAuthOrderId());
        XpOrder order = this.getOne(wrapper.last("LIMIT 1"));
        if(dto.getPayStatus()==1){
            order.setStatus(9);
            order.setAppUserId(null);
            this.updateById(order);
            CreditPayCallVo vo = new CreditPayCallVo();
            vo.setRetCode("0");
            vo.setRetMsg("成功");
            // 对接财务
            this.xpFrdXfipEventPush(order,dto.getPayFee(),dto.getOrderId());
            return vo;
        }
        return null;
    }
    /**
     * 发票列表
@@ -5162,9 +5577,6 @@
        ArrayList<XpInvoiceVo> xpInvoiceVoList = new ArrayList<>(list.size());
        R<List<XpVehicle>> r = xpVehicleClient.listByIds(list.stream().map(XpOrder::getVehicleId).collect(Collectors.toList()));
        List<XpVehicle> vehicleList = r.getData();
        // 数据组装
        for (XpOrder xpOrder : list) {
            XpInvoiceVo xpInvoiceVo = new XpInvoiceVo();
@@ -5187,7 +5599,9 @@
            goodsDetail.setItemId(xpOrder.getOrderNumber());
            goodsDetail.setCouponAmount(xpOrder.getCouponMoney());
            goodsDetail.setCompanyCode("8000");
            xpInvoiceVo.setGoodsDetail(JSON.toJSONString(goodsDetail));
            JSONArray goodsDetailArray = new JSONArray();
            goodsDetailArray.add(goodsDetail);
            xpInvoiceVo.setGoodsDetail(JSON.toJSONString(goodsDetailArray));
            xpInvoiceVo.setOrderTotalAmount(xpOrder.getOrderMoney()!=null?xpOrder.getOrderMoney():BigDecimal.ZERO);
            xpInvoiceVo.setOrderBusAmount(xpOrder.getOrderMoney()!=null?xpOrder.getOrderMoney():BigDecimal.ZERO);
@@ -5220,6 +5634,16 @@
            itinerary.setEndPoint(xpOrder.getEndAddress());
            itinerary.setMileage(xpOrder.getMileageKilometers()!=null ? xpOrder.getMileageKilometers().toString() :"0");
            UcUserInfo user = userResourcesClient.getBaseUserByUid(xpOrder.getAppUserId().toString());
            itinerary.setUserName(user.getNickName());
            itinerary.setUserAccount(user.getUid().toString());
            itinerary.setPhone(user.getMobile());
            itinerary.setPickupTime(xpOrder.getBoardingTime()!=null?xpOrder.getBoardingTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")):"");
            itinerary.setDropOffTime(xpOrder.getTripEnd()!=null?xpOrder.getTripEnd().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")):"");
            itinerary.setOldPrice(xpOrder.getOrderMoney()!=null?xpOrder.getOrderMoney().toString():"0");
            itinerary.setCurrency("CNY");
            xpInvoiceVo.setItinerary(itinerary);
            xpInvoiceVoList.add(xpInvoiceVo);
        }
@@ -5246,9 +5670,6 @@
        ArrayList<XpInvoiceVo> xpInvoiceVoList = new ArrayList<>(list.size());
        R<List<XpVehicle>> r = xpVehicleClient.listByIds(list.stream().map(XpOrder::getVehicleId).collect(Collectors.toList()));
        List<XpVehicle> vehicleList = r.getData();
        // 数据组装
        for (XpOrder xpOrder : list) {
            XpInvoiceVo xpInvoiceVo = new XpInvoiceVo();
@@ -5271,13 +5692,18 @@
            goodsDetail.setItemId(xpOrder.getOrderNumber());
            goodsDetail.setCouponAmount(xpOrder.getCouponMoney());
            goodsDetail.setCompanyCode("8000");
            xpInvoiceVo.setGoodsDetail(JSON.toJSONString(goodsDetail));
            JSONArray goodsDetailArray = new JSONArray();
            goodsDetailArray.add(goodsDetail);
            xpInvoiceVo.setGoodsDetail(JSON.toJSONString(goodsDetailArray));
            xpInvoiceVo.setOrderTotalAmount(xpOrder.getPayMoney());
            xpInvoiceVo.setOrderBusAmount(xpOrder.getOrderMoney());
            xpInvoiceVo.setOrderDiscountAmount(xpOrder.getCouponMoney());
            xpInvoiceVo.setOrderFinishTime(xpOrder.getTripEnd()!=null?String.valueOf(xpOrder.getTripEnd()):"");
            xpInvoiceVo.setOrderTotalAmount(xpOrder.getOrderMoney()!=null?xpOrder.getOrderMoney():BigDecimal.ZERO);
            xpInvoiceVo.setOrderBusAmount(xpOrder.getOrderMoney()!=null?xpOrder.getOrderMoney():BigDecimal.ZERO);
            xpInvoiceVo.setOrderDiscountAmount(xpOrder.getCouponMoney()!=null?xpOrder.getCouponMoney():BigDecimal.ZERO);
            xpInvoiceVo.setOrderFinishTime(xpOrder.getTripEnd()!=null?xpOrder.getTripEnd().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")):"");
            JSONObject extData = new JSONObject();
@@ -5302,6 +5728,16 @@
            itinerary.setStartPoint(xpOrder.getStartAddress());
            itinerary.setEndPoint(xpOrder.getEndAddress());
            itinerary.setMileage(xpOrder.getMileageKilometers()!=null ? xpOrder.getMileageKilometers().toString() :"0");
            UcUserInfo user = userResourcesClient.getBaseUserByUid(xpOrder.getAppUserId().toString());
            itinerary.setUserName(user.getNickName());
            itinerary.setUserAccount(user.getUid().toString());
            itinerary.setPhone(user.getMobile());
            itinerary.setPickupTime(xpOrder.getBoardingTime()!=null?xpOrder.getBoardingTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")):"");
            itinerary.setDropOffTime(xpOrder.getTripEnd()!=null?xpOrder.getTripEnd().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")):"");
            itinerary.setOldPrice(xpOrder.getOrderMoney()!=null?xpOrder.getOrderMoney().toString():"0");
            itinerary.setCurrency("CNY");
            xpInvoiceVo.setItinerary(itinerary);
            xpInvoiceVoList.add(xpInvoiceVo);