yyy
2026-05-06 b59bca62353f93424818a4dd39068b10948c5267
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -172,7 +172,7 @@
    private final IXpTestOrderService xpTestOrderService;
    private final XpMapClient xpMapClient;
    @Resource
    private  XpRoutePlanClient xpRoutePlanClient;
    private XpRoutePlanClient xpRoutePlanClient;
    @Resource
    @Lazy
    private BootCommonService bootCommonService;
@@ -194,6 +194,9 @@
    @Resource
    private XpTradingStrategyClient tradingStrategyClient;
    @Resource
    private OfficialPartnerUtil officialPartnerUtil;
    @Value("${robotaxi.appId:xp_robotaxi_api}")
    private String appid;
@@ -264,7 +267,7 @@
        }
        wrapper.eq(Objects.nonNull(query.getUid()), XpOrder::getAppUserId, query.getUid());
        wrapper.orderByDesc(XpOrder::getCreateTime);
        if(null != query.getActivityId()){
        if (null != query.getActivityId()) {
            wrapper.eq(XpOrder::getActivityId, query.getActivityId());
        }
@@ -573,7 +576,7 @@
    @Override
    @Transactional
    @ShardingSphereTransactionType(TransactionType.BASE)
    public void cancelOrCloseOrder(Long orderId, Integer type,Boolean isFree) {
    public void cancelOrCloseOrder(Long orderId, Integer type, Boolean isFree) {
        // 1. 校验订单是否存在
        XpOrder order = this.getById(orderId);
        if (Objects.isNull(order)) {
@@ -594,7 +597,7 @@
                throw new ServiceException("当前订单状态不允许取消,只有待接单、待出发、接驾中状态的订单可以取消", I18nKeyConstant.ORDER_CANCEL_FAILED);
            }
        } else {
            if(isFree == null){
            if (isFree == null) {
                throw new ServiceException("是否豁免费用不能为空", I18nKeyConstant.ORDER_CLOSE_FAILED);
            }
            // 关闭订单:0=已取消,1=待接单,2=待出发,3=接驾中,4=待客上车,5=乘客已上车,6=服务中 状态可以关闭
@@ -610,7 +613,7 @@
        } else {
            // 关闭订单
            closeOrder(order);
            if(isFree){
            if (isFree) {
                this.setFree(order.getId());
            }
        }
@@ -668,22 +671,6 @@
     */
    private void cancelOrder(XpOrder order) {
        redisService.removeByPattern(order.getQueueName(), order.getOrderNumber());
        //判断还原车辆状态
        if (null == order.getVehicleId()) {
            Object cacheObject1 = redisService.getCacheObject("CREATE_ORDER:" + order.getId().toString());
            if (null != cacheObject1) {
                com.alibaba.fastjson2.JSONObject jsonObject = com.alibaba.fastjson2.JSON.parseObject(cacheObject1.toString());
                String vin = jsonObject.getString("vin");
                XpVehicle vehicle = xpVehicleClient.findByVehicleVin(vin).getData();
                if (null != vehicle && 0 != vehicle.getState()) {
                    XpVehicle vehicle1 = new XpVehicle();
                    vehicle1.setId(vehicle.getId());
                    vehicle1.setState(0);
                    xpVehicleClient.updateVehicleById(vehicle1);
                    log.info("管理后台取消订单,车辆状态修改0 {}", vehicle.getPlateNumber());
                }
            }
        }
        Long userId = order.getAppUserId();
        Integer status = order.getStatus();
@@ -693,19 +680,21 @@
            order.setAppUserId(null);
            baseMapper.updateById(order);
            order.setAppUserId(appUserId);
            bootCommonService.setCache_orderStatus(order.getId(),order,null);
            //删除蓝牙秘钥
            String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
            if(StringUtils.isNotBlank(token)){
                redisService.deleteObject("rt:bluetooth:unlock:" + token);
                redisService.deleteObject("rt:bluetooth:unlock:order:" + order.getId());
                XpVehicle xpVehicle = xpVehicleClient.queryById(order.getVehicleId()).getData();
                BluetoothDeliverVo vo = new BluetoothDeliverVo();
                vo.setVim(xpVehicle.getVehicleVin());
                vo.setPassengerUid(order.getAppUserId());
                BaseVehicleUserDto delete = bluetoothUnlockClient.delete(vo);
                if(null == delete || delete.getCode() != 0){
                    log.error("删除蓝牙解锁失败:{} {}", delete.getMsg(), order.getOrderNumber());
            bootCommonService.setCache_orderStatus(order.getId(), order, null);
            if(null == order.getOfficialPartnerId()){
                //删除蓝牙秘钥
                String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
                if (StringUtils.isNotBlank(token)) {
                    redisService.deleteObject("rt:bluetooth:unlock:" + token);
                    redisService.deleteObject("rt:bluetooth:unlock:order:" + order.getId());
                    XpVehicle xpVehicle = xpVehicleClient.queryById(order.getVehicleId()).getData();
                    BluetoothDeliverVo vo = new BluetoothDeliverVo();
                    vo.setVim(xpVehicle.getVehicleVin());
                    vo.setPassengerUid(order.getAppUserId());
                    BaseVehicleUserDto delete = bluetoothUnlockClient.delete(vo);
                    if (null == delete || delete.getCode() != 0) {
                        log.error("删除蓝牙解锁失败:{} {}", delete.getMsg(), order.getOrderNumber());
                    }
                }
            }
            // 消息推送
@@ -723,12 +712,12 @@
            R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
            //推送失败,重试3次
            if(stringR.getCode() != Constants.SUCCESS){
            if (stringR.getCode() != Constants.SUCCESS) {
                ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
                executor.execute(() -> {
                    for (int i = 0; i < 3; i++) {
                        R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                        if(stringR1.getCode() == Constants.SUCCESS){
                        if (stringR1.getCode() == Constants.SUCCESS) {
                            break;
                        }
                        try {
@@ -748,7 +737,7 @@
                .eq(XpOrder::getId, order.getId()).update();
        order.setStatus(OrderStatusEnum.CANCELED.getCode());
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        bootCommonService.setCache_orderStatus(order.getId(), order, null);
        // 2. 保存取消记录
        XpOrderCancel orderCancel = new XpOrderCancel();
@@ -771,12 +760,12 @@
        sendMessageDTO.setAppUserId(String.valueOf(userId));
        R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
        //推送失败,重试3次
        if(stringR.getCode() != Constants.SUCCESS){
        if (stringR.getCode() != Constants.SUCCESS) {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                    if(stringR1.getCode() == Constants.SUCCESS){
                    if (stringR1.getCode() == Constants.SUCCESS) {
                        break;
                    }
                    try {
@@ -790,45 +779,68 @@
        }
        log.info("运营人员取消订单成功,推送乘客消息完成");
        //查询车辆信息
        R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(order.getVehicleId());
        if (xpVehicleR.getCode() == HttpStatus.SUCCESS && Objects.nonNull(xpVehicleR.getData())) {
            XpVehicle xpVehicle = xpVehicleR.getData();
            // 组装调用车机参数
            CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo();
            cancelTaxiPassengerVo.setVin(xpVehicle.getVehicleVin());
            cancelTaxiPassengerVo.setUid(userId.toString());
            cancelTaxiPassengerVo.setOrderNo(order.getOrderNumber());
            cancelTaxiPassengerVo.setAppId(appid);
            BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
            if (baseVehicleUserDto == null) {
                // TODO 本地无法调通
        if(null == order.getOfficialPartnerId()){
            //判断还原车辆状态
            if (null == order.getVehicleId()) {
                Object cacheObject1 = redisService.getCacheObject("CREATE_ORDER:" + order.getId().toString());
                if (null != cacheObject1) {
                    com.alibaba.fastjson2.JSONObject jsonObject = com.alibaba.fastjson2.JSON.parseObject(cacheObject1.toString());
                    String vin = jsonObject.getString("vin");
                    XpVehicle vehicle = xpVehicleClient.findByVehicleVin(vin).getData();
                    if (null != vehicle && 0 != vehicle.getState()) {
                        XpVehicle vehicle1 = new XpVehicle();
                        vehicle1.setId(vehicle.getId());
                        vehicle1.setState(0);
                        xpVehicleClient.updateVehicleById(vehicle1);
                        log.info("管理后台取消订单,车辆状态修改0 {}", vehicle.getPlateNumber());
                    }
                }
            }
            //查询车辆信息
            R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(order.getVehicleId());
            if (xpVehicleR.getCode() == HttpStatus.SUCCESS && Objects.nonNull(xpVehicleR.getData())) {
                XpVehicle xpVehicle = xpVehicleR.getData();
                // 组装调用车机参数
                CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo();
                cancelTaxiPassengerVo.setVin(xpVehicle.getVehicleVin());
                cancelTaxiPassengerVo.setUid(userId.toString());
                cancelTaxiPassengerVo.setOrderNo(order.getOrderNumber());
                cancelTaxiPassengerVo.setAppId(appid);
                BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
                if (baseVehicleUserDto == null) {
                    // TODO 本地无法调通
//            throw new RuntimeException("取消订单失败");
            }
                }
            //还原车辆状态
            if(1 == xpVehicle.getState()){
                XpVehicle vehicle1 = new XpVehicle();
                vehicle1.setId(xpVehicle.getId());
                vehicle1.setState(0);
                xpVehicleClient.updateVehicleById(vehicle1);
                log.info("管理后台取消订单,车辆状态修改0 {}", xpVehicle.getPlateNumber());
            }
                //还原车辆状态
                if (1 == xpVehicle.getState()) {
                    XpVehicle vehicle1 = new XpVehicle();
                    vehicle1.setId(xpVehicle.getId());
                    vehicle1.setState(0);
                    xpVehicleClient.updateVehicleById(vehicle1);
                    log.info("管理后台取消订单,车辆状态修改0 {}", xpVehicle.getPlateNumber());
                }
            // 下发命令
                // 下发命令
//            PushOrderDto pushOrderDto = new PushOrderDto();
//            pushOrderDto.setOrderId(order.getId().toString());
//            pushOrderDto.setVin(xpVehicle.getVehicleVin());
//            pushOrderDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
//            orderMissionClient.cancelOrder(pushOrderDto);
//            log.info("运营人员取消订单成功,开始执行巡游订单 {}", order.getId());
            //车辆继续巡游
            addCruiseMission(order, status);
                //车辆继续巡游
                addCruiseMission(order, status);
        } else {
            log.info("查询车辆信息失败,订单ID: {}, 下发取消订单命令失败", order.getId());
            } else {
                log.info("查询车辆信息失败,订单ID: {}, 下发取消订单命令失败", order.getId());
            }
            log.info("订单取消成功,订单ID: {}, 操作人: {}", order.getId(), SecurityUtils.getUsername());
        }else{
            //流量接入-订单推送 推送取消订单
            officialPartnerUtil.pushCancelOrder(order.getOfficialPartnerId(), orderCancel, order.getStatus());
        }
        log.info("订单取消成功,订单ID: {}, 操作人: {}", order.getId(), SecurityUtils.getUsername());
    }
    /**
@@ -840,9 +852,9 @@
        order.setGetoffTime(LocalDateTime.now());
        // 解析下车地点
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
        if(Objects.nonNull(vehiclePosition)){
        if (Objects.nonNull(vehiclePosition)) {
            GeoJsonPoint point = vehiclePosition.getPoint();
            if(Objects.nonNull(point)){
            if (Objects.nonNull(point)) {
                double x = point.getX();
                double y = point.getY();
                Map<String, String> geocode = gdMapGeocodingUtil.geocode(String.valueOf(x), String.valueOf(y));
@@ -859,7 +871,7 @@
        order.setAppUserId(null);
        this.updateById(order);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        bootCommonService.setCache_orderStatus(order.getId(), order, null);
        // 消息推送
        Map<String, Object> params1 = new HashMap<>();
@@ -875,12 +887,12 @@
        sendMessageDTO1.setAppUserId(appUserId.toString());
        R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO1);
        //推送失败,重试3次
        if(stringR1.getCode() != Constants.SUCCESS){
        if (stringR1.getCode() != Constants.SUCCESS) {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR2 = xpPushMessageClient.sendStatus(sendMessageDTO1);
                    if(stringR2.getCode() == Constants.SUCCESS){
                    if (stringR2.getCode() == Constants.SUCCESS) {
                        break;
                    }
                    try {
@@ -907,12 +919,12 @@
        sendMessageDTO.setAppUserId(appUserId.toString());
        R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
        //推送失败,重试3次
        if(stringR.getCode() != Constants.SUCCESS){
        if (stringR.getCode() != Constants.SUCCESS) {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR2 = xpPushMessageClient.sendStatus(sendMessageDTO);
                    if(stringR2.getCode() == Constants.SUCCESS){
                    if (stringR2.getCode() == Constants.SUCCESS) {
                        break;
                    }
                    try {
@@ -949,12 +961,12 @@
        sendMessageDTO2.setAppUserId(appUserId.toString());
        R<String> stringR2 = xpPushMessageClient.sendStatus(sendMessageDTO2);
        //推送失败,重试3次
        if(stringR2.getCode() != Constants.SUCCESS){
        if (stringR2.getCode() != Constants.SUCCESS) {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR3 = xpPushMessageClient.sendStatus(sendMessageDTO2);
                    if(stringR3.getCode() == Constants.SUCCESS){
                    if (stringR3.getCode() == Constants.SUCCESS) {
                        break;
                    }
                    try {
@@ -967,20 +979,25 @@
            });
        }
        //创建定时任务执行延迟驶离终点和下发巡游单
        XpPoint point = xpPointClient.queryById(order.getEndPointId()).getData();
        Map<String, ? extends Object> jobMaps =
                new ImmutableMap.Builder<String, String>()
                        .put("id", order.getId().toString())
                        .put("appid", appid)
                        .build();
        QuartzManager.addJob(
                AddCruiseMissionJob.class,
                (AddCruiseMissionJob.name + order.getId()).toUpperCase(),
                TimeJobType.ADD_CRUISE_MISSION,
                DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(point.getParkingTimeLimit())),
                jobMaps
        );
        if(order.getOfficialPartnerId() == null){
            //创建定时任务执行延迟驶离终点和下发巡游单
            XpPoint point = xpPointClient.queryById(order.getEndPointId()).getData();
            Map<String, ? extends Object> jobMaps =
                    new ImmutableMap.Builder<String, String>()
                            .put("id", order.getId().toString())
                            .put("appid", appid)
                            .build();
            QuartzManager.addJob(
                    AddCruiseMissionJob.class,
                    (AddCruiseMissionJob.name + order.getId()).toUpperCase(),
                    TimeJobType.ADD_CRUISE_MISSION,
                    DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(point.getParkingTimeLimit())),
                    jobMaps
            );
        }else{
            //流量接入-订单推送 推送关闭订单
            officialPartnerUtil.pushEndOrder(order.getOfficialPartnerId(), order, "运维人员关闭订单");
        }
    }
    /**
@@ -1017,14 +1034,14 @@
        if (Objects.isNull(newVehicle.getState()) || newVehicle.getState() != 0) {
            throw new ServiceException("新车辆已接单,请重新选择", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_FREE);
        }
        if (newVehicle.getOperatingStatus() != 1){
        if (newVehicle.getOperatingStatus() != 1) {
            throw new ServiceException("新车辆状态为非运营状态,请重新选择", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_OPERATIONAL);
        }
        VehiclePosition vehiclePosition = mongoTemplate.findOne(Query.query(Criteria.where("vin").is(newVehicle.getVehicleVin())), VehiclePosition.class);
        if(null == vehiclePosition){
        if (null == vehiclePosition) {
            throw new ServiceException("未能获取到新车的定位数据,请重新选择", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_NOT_POSITION);
        }
        if(vehiclePosition.getCurrentElectricity() < 20){
        if (vehiclePosition.getCurrentElectricity() < 20) {
            throw new ServiceException("新车电量不足,请重新选择", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_BATTERY_LOW);
        }
@@ -1231,7 +1248,7 @@
     * - 其他状态,默认返回原出发点
     * </p>
     *
     * @param order      当前订单信息
     * @param order 当前订单信息
     */
    private void createReturnCruiseOrder(Long vehicleId, XpOrder order) {
        XpVehicle oldVehicle = xpVehicleClient.queryById(vehicleId).getData();
@@ -1364,6 +1381,7 @@
    @Resource
    private XpAppUserCollectAddrClient xpAppUserCollectAddrClient;
    @Override
    public NearestNextVo quickCapsule(String uid, Long startPointId) {
@@ -1405,7 +1423,7 @@
                ret.setTime(endPoint.getParkingTimeLimit());
                ret.setElectronicAreaId(endPoint.getElectronicAreaId());
                // 判断是否收藏
                if(pointIdsByUserId.contains(endPoint.getId())){
                if (pointIdsByUserId.contains(endPoint.getId())) {
                    ret.setIsCollect(1);
                }
                return ret;
@@ -1611,9 +1629,9 @@
    }
    @Override
    public List<XpHistoryStartPointsVo> getHistoryStartPoints(String uid, double lon, double lat,Long electronicAreaId) {
    public List<XpHistoryStartPointsVo> getHistoryStartPoints(String uid, double lon, double lat, Long electronicAreaId) {
        //
        List<XpOrder> xpOrders = this.baseMapper.getHistoryStartPoints(Long.valueOf(uid),electronicAreaId);
        List<XpOrder> xpOrders = this.baseMapper.getHistoryStartPoints(Long.valueOf(uid), electronicAreaId);
//        selectList(new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, Long.parseLong(uid)).orderByDesc(BaseModel::getCreateTime).last("LIMIT 10"));
        if (xpOrders.isEmpty()) {
            return Collections.emptyList();
@@ -1621,7 +1639,7 @@
        // 获取点位信息
        List<Long> startPointsIds = xpOrders.stream().map(XpOrder::getStartPointId).collect(Collectors.toList());
        R<List<XpHistoryStartPointsVo>> r = xpPointClient.getHistoryStartPoints(new HistoryStartPointsDto(startPointsIds, lon, lat,Long.valueOf(uid)));
        R<List<XpHistoryStartPointsVo>> r = xpPointClient.getHistoryStartPoints(new HistoryStartPointsDto(startPointsIds, lon, lat, Long.valueOf(uid)));
        List<XpHistoryStartPointsVo> data = r.getData();
@@ -1649,7 +1667,7 @@
    }
    @Override
    public List<XpHistoryEndPointsVo> getHistoryEndPoints(String uid, double lon, double lat,Long electronicAreaId) {
    public List<XpHistoryEndPointsVo> getHistoryEndPoints(String uid, double lon, double lat, Long electronicAreaId) {
        //
        List<XpOrder> xpOrders = this.baseMapper.getHistoryEndPoints(Long.valueOf(uid), electronicAreaId);
//        selectList(new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, Long.parseLong(uid)).orderByDesc(BaseModel::getCreateTime).last("LIMIT 10"));
@@ -1659,7 +1677,7 @@
        // 获取点位信息
        List<Long> endPointsIds = xpOrders.stream().map(XpOrder::getEndPointId).collect(Collectors.toList());
        R<List<XpHistoryEndPointsVo>> r = xpPointClient.getHistoryEndPoints(new HistoryEndPointsDto(endPointsIds, lon, lat,Long.valueOf(uid)));
        R<List<XpHistoryEndPointsVo>> r = xpPointClient.getHistoryEndPoints(new HistoryEndPointsDto(endPointsIds, lon, lat, Long.valueOf(uid)));
        List<XpHistoryEndPointsVo> data = r.getData();
@@ -1774,78 +1792,13 @@
            e.printStackTrace();
        }
        Integer status = order.getStatus();
        //判断还原车辆状态
        if (null == order.getVehicleId()) {
            Object cacheObject1 = redisService.getCacheObject("CREATE_ORDER:" + order.getId().toString());
            if (null != cacheObject1) {
                JSONObject jsonObject = JSON.parseObject(cacheObject1.toString());
                String vin = jsonObject.getString("vin");
                XpVehicle vehicle = xpVehicleClient.findByVehicleVin(vin).getData();
                if (null != vehicle && 0 != vehicle.getState()) {
                    XpVehicle vehicle1 = new XpVehicle();
                    vehicle1.setId(vehicle.getId());
                    vehicle1.setState(0);
                    xpVehicleClient.updateVehicleById(vehicle1);
                    log.info("用户取消订单,车辆状态修改0 {}", vehicle.getPlateNumber());
                }
            }
        }
        else{// 下发命令
            R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(order.getVehicleId());
            XpVehicle xpVehicle = xpVehicleR.getData();
            if (xpVehicle == null) {
                throw new ServiceException("车辆不存在", I18nKeyConstant.VEHICLE_NOT_EXISTS);
            }
            //是否能取消行程
            boolean cancelShow = this.isCancelShow(order,xpVehicle.getVehicleVin());
            if(cancelShow){
                throw new ServiceException("当前订单状态不允许取消,行程即将完成", I18nKeyConstant.ORDER_CANCEL_FAILED);
            }
            // 组装调用车机参数
            CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo();
            cancelTaxiPassengerVo.setVin(xpVehicle.getVehicleVin());
            cancelTaxiPassengerVo.setUid(uid);
            cancelTaxiPassengerVo.setOrderNo(order.getOrderNumber());
            cancelTaxiPassengerVo.setAppId(appid);
            BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
            if (baseVehicleUserDto == null) {
                // TODO 本地无法调通
//            throw new RuntimeException("取消订单失败");
            }
            //还原车辆状态
            if (1 == xpVehicle.getState()) {
                XpVehicle vehicle1 = new XpVehicle();
                vehicle1.setId(xpVehicle.getId());
                vehicle1.setState(0);
                xpVehicleClient.updateVehicleById(vehicle1);
                log.info("用户取消订单,车辆状态修改0 {}", xpVehicle.getPlateNumber());
            }
            //车辆继续巡游
            addCruiseMission(order, status);
        }
        order.setStatus(0);
        Long appUserId = order.getAppUserId();
        order.setAppUserId(null);
        baseMapper.updateById(order);
        order.setAppUserId(appUserId);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        //删除蓝牙秘钥
        String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
        if(StringUtils.isNotBlank(token)){
            redisService.deleteObject("rt:bluetooth:unlock:" + token);
            redisService.deleteObject("rt:bluetooth:unlock:order:" + order.getId());
            XpVehicle xpVehicle = xpVehicleClient.queryById(order.getVehicleId()).getData();
            BluetoothDeliverVo vo = new BluetoothDeliverVo();
            vo.setVim(xpVehicle.getVehicleVin());
            vo.setPassengerUid(order.getAppUserId());
            BaseVehicleUserDto delete = bluetoothUnlockClient.delete(vo);
            if(null == delete || delete.getCode() != 0){
                log.error("删除蓝牙解锁失败:{} {}", delete.getMsg(), order.getOrderNumber());
            }
        }
        bootCommonService.setCache_orderStatus(order.getId(), order, null);
        XpOrderCancel xpOrderCancel = new XpOrderCancel();
        xpOrderCancel.setOrderId(orderId);
@@ -1855,6 +1808,78 @@
        xpOrderCancelService.save(xpOrderCancel);
        // 移除mongo数据
        xpPricingClient.deleteXpGeoQueryEntity(order.getId().toString());
        if(null == order.getOfficialPartnerId()){
            //判断还原车辆状态
            if (null == order.getVehicleId()) {
                Object cacheObject1 = redisService.getCacheObject("CREATE_ORDER:" + order.getId().toString());
                if (null != cacheObject1) {
                    JSONObject jsonObject = JSON.parseObject(cacheObject1.toString());
                    String vin = jsonObject.getString("vin");
                    XpVehicle vehicle = xpVehicleClient.findByVehicleVin(vin).getData();
                    if (null != vehicle && 0 != vehicle.getState()) {
                        XpVehicle vehicle1 = new XpVehicle();
                        vehicle1.setId(vehicle.getId());
                        vehicle1.setState(0);
                        xpVehicleClient.updateVehicleById(vehicle1);
                        log.info("用户取消订单,车辆状态修改0 {}", vehicle.getPlateNumber());
                    }
                }
            } else {// 下发命令
                R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(order.getVehicleId());
                XpVehicle xpVehicle = xpVehicleR.getData();
                if (xpVehicle == null) {
                    throw new ServiceException("车辆不存在", I18nKeyConstant.VEHICLE_NOT_EXISTS);
                }
                //是否能取消行程
                boolean cancelShow = this.isCancelShow(order, xpVehicle.getVehicleVin());
                if (cancelShow) {
                    throw new ServiceException("当前订单状态不允许取消,行程即将完成", I18nKeyConstant.ORDER_CANCEL_FAILED);
                }
                // 组装调用车机参数
                CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo();
                cancelTaxiPassengerVo.setVin(xpVehicle.getVehicleVin());
                cancelTaxiPassengerVo.setUid(uid);
                cancelTaxiPassengerVo.setOrderNo(order.getOrderNumber());
                cancelTaxiPassengerVo.setAppId(appid);
                BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
                if (baseVehicleUserDto == null) {
                    // TODO 本地无法调通
//            throw new RuntimeException("取消订单失败");
                }
                //还原车辆状态
                if (1 == xpVehicle.getState()) {
                    XpVehicle vehicle1 = new XpVehicle();
                    vehicle1.setId(xpVehicle.getId());
                    vehicle1.setState(0);
                    xpVehicleClient.updateVehicleById(vehicle1);
                    log.info("用户取消订单,车辆状态修改0 {}", xpVehicle.getPlateNumber());
                }
                //车辆继续巡游
                addCruiseMission(order, status);
            }
            //删除蓝牙秘钥
            String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
            if (StringUtils.isNotBlank(token)) {
                redisService.deleteObject("rt:bluetooth:unlock:" + token);
                redisService.deleteObject("rt:bluetooth:unlock:order:" + order.getId());
                XpVehicle xpVehicle = xpVehicleClient.queryById(order.getVehicleId()).getData();
                BluetoothDeliverVo vo = new BluetoothDeliverVo();
                vo.setVim(xpVehicle.getVehicleVin());
                vo.setPassengerUid(order.getAppUserId());
                BaseVehicleUserDto delete = bluetoothUnlockClient.delete(vo);
                if (null == delete || delete.getCode() != 0) {
                    log.error("删除蓝牙解锁失败:{} {}", delete.getMsg(), order.getOrderNumber());
                }
            }
        }else{
            //流量接入-订单推送 推送取消订单
            officialPartnerUtil.pushCancelOrder(order.getOfficialPartnerId(), xpOrderCancel, order.getStatus());
        }
    }
    @Override
@@ -1870,19 +1895,21 @@
        order.setAppUserId(null);
        baseMapper.updateById(order);
        order.setAppUserId(appUserId);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        //删除蓝牙秘钥
        String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
        if(StringUtils.isNotBlank(token)){
            redisService.deleteObject("rt:bluetooth:unlock:" + token);
            redisService.deleteObject("rt:bluetooth:unlock:order:" + order.getId());
            XpVehicle xpVehicle = xpVehicleClient.queryById(order.getVehicleId()).getData();
            BluetoothDeliverVo vo = new BluetoothDeliverVo();
            vo.setVim(xpVehicle.getVehicleVin());
            vo.setPassengerUid(order.getAppUserId());
            BaseVehicleUserDto delete = bluetoothUnlockClient.delete(vo);
            if(null == delete || delete.getCode() != 0){
                log.error("删除蓝牙解锁失败:{} {}", delete.getMsg(), order.getOrderNumber());
        bootCommonService.setCache_orderStatus(order.getId(), order, null);
        if(null == order.getOfficialPartnerId()){
            //删除蓝牙秘钥
            String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + order.getId());
            if (StringUtils.isNotBlank(token)) {
                redisService.deleteObject("rt:bluetooth:unlock:" + token);
                redisService.deleteObject("rt:bluetooth:unlock:order:" + order.getId());
                XpVehicle xpVehicle = xpVehicleClient.queryById(order.getVehicleId()).getData();
                BluetoothDeliverVo vo = new BluetoothDeliverVo();
                vo.setVim(xpVehicle.getVehicleVin());
                vo.setPassengerUid(order.getAppUserId());
                BaseVehicleUserDto delete = bluetoothUnlockClient.delete(vo);
                if (null == delete || delete.getCode() != 0) {
                    log.error("删除蓝牙解锁失败:{} {}", delete.getMsg(), order.getOrderNumber());
                }
            }
        }
@@ -1910,12 +1937,12 @@
        sendMessageDTO.setAppUserId(String.valueOf(appUserId));
        R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
        //推送失败,重试3次
        if(stringR.getCode() != Constants.SUCCESS){
        if (stringR.getCode() != Constants.SUCCESS) {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                    if(stringR1.getCode() == Constants.SUCCESS){
                    if (stringR1.getCode() == Constants.SUCCESS) {
                        break;
                    }
                    try {
@@ -1933,6 +1960,11 @@
        // 移除mongo数据
        xpPricingClient.deleteXpGeoQueryEntity(order.getId().toString());
        //流量接入-订单推送 推送取消订单
        if(Objects.nonNull(order.getOfficialPartnerId())){
            officialPartnerUtil.pushCancelOrder(order.getOfficialPartnerId(), xpOrderCancel, order.getStatus());
        }
        return order;
    }
@@ -1959,7 +1991,7 @@
        xpOrder.setAppUserId(null);
        xpOrder.setStatus(10);
        baseMapper.updateById(xpOrder);
        bootCommonService.setCache_orderStatus(xpOrder.getId(),xpOrder,null);
        bootCommonService.setCache_orderStatus(xpOrder.getId(), xpOrder, null);
        XpOrderEvaluate evaluate = new XpOrderEvaluate();
        evaluate.setOrderId(xpOrder.getId());
@@ -1983,19 +2015,20 @@
        if (xpOrder.getStatus() == 0) {
            return R.fail("订单已取消");
        }
        if(xpOrder.getStatus() >= 8){
        if (xpOrder.getStatus() >= 8) {
            return R.fail("订单已结束");
        }
        Long appUserId = xpOrder.getAppUserId();
        // 查询车辆
        XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
//        订单的状态 status =1 ( 状态 0=已取消,1=待接单,2=待出发,3=接驾中,4=待客上车,5=乘客已上车,6=服务中,7=待客下车,8=待付款,9=待评价,10=已完成)
        switch (status) {
            case 0://去掉订单 优惠卷需要返回 @todo yyy 这里可能不需要这个步骤
                //取消订单会将优惠卷 从占用修改成未使用
                if(xpOrder.getCouponId() != null){
                if (xpOrder.getCouponId() != null) {
                    UseUserCouponDto useUserCouponDto = new UseUserCouponDto();
                    useUserCouponDto.setUserCouponId(xpOrder.getCouponId() );
                    useUserCouponDto.setUserCouponId(xpOrder.getCouponId());
                    xpAppUserCouponClient.backUserCoupon(useUserCouponDto);
                }
                break;
@@ -2021,6 +2054,17 @@
            case 5:
                LocalDateTime now = LocalDateTime.now();
                xpOrder.setBoardingTime(now);
                if (Objects.nonNull(vehiclePosition)) {
                    GeoJsonPoint point = vehiclePosition.getPoint();
                    if (Objects.nonNull(point)) {
                        double x = point.getX();
                        double y = point.getY();
                        Map<String, String> geocode = gdMapGeocodingUtil.geocode(String.valueOf(x), String.valueOf(y));
                        xpOrder.setBoardingLon(x);
                        xpOrder.setBoardingLat(y);
                        xpOrder.setBoardingAddress(geocode.get("address"));
                    }
                }
                xpOrder.setRideTime(now);
                //推送行起点到终点的驶轨迹给乘客端
                sendRoute(appUserId.toString(), orderId, "ORDER_NAVIGATION_END_DATA", xpVehicle.getVehicleVin());
@@ -2029,7 +2073,7 @@
                //乘客已上车,重新倒计时不开始行程取消订单
                XpPoint xpPoint1 = xpPointClient.queryById(xpOrder.getStartPointId()).getData();
                XpTradingStrategy tradingStrategy = tradingStrategyClient.getTradingStrategyByCityCode(xpPoint1.getCityCode()).getData();
                if(null != tradingStrategy){
                if (null != tradingStrategy) {
                    Map<String, ? extends Object> cancelJobMaps1 =
                            new ImmutableMap.Builder<String, Long>().
                                    put("id", xpOrder.getId())
@@ -2042,9 +2086,6 @@
                            cancelJobMaps1
                    );
                }
                // 车辆到达上车点时间
                xpOrder.setArrivalTime(LocalDateTime.now());
                break;
            case 6:
                // 删除定时任务job
@@ -2053,7 +2094,7 @@
                xpOrder.setTripBegin(LocalDateTime.now());
                //添加预估到达时间
                String cacheObject = redisService.getCacheObject("ORDER_NAVIGATION_END_DATA:" + xpOrder.getAppUserId());
                if(StringUtils.isNotBlank(cacheObject)){
                if (StringUtils.isNotBlank(cacheObject)) {
                    RouteVo routeVo = JSONObject.parseObject(cacheObject, RouteVo.class);
                    xpOrder.setEstimatedArrivalTime(LocalDateTime.now().plusSeconds(routeVo.getDuration()));
                }
@@ -2062,10 +2103,9 @@
            case 7:
                xpOrder.setGetoffTime(LocalDateTime.now());
                // 解析下车地点
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
                if(Objects.nonNull(vehiclePosition)){
                if (Objects.nonNull(vehiclePosition)) {
                    GeoJsonPoint point = vehiclePosition.getPoint();
                    if(Objects.nonNull(point)){
                    if (Objects.nonNull(point)) {
                        double x = point.getX();
                        double y = point.getY();
                        Map<String, String> geocode = gdMapGeocodingUtil.geocode(String.valueOf(x), String.valueOf(y));
@@ -2093,12 +2133,12 @@
                sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId()));
                R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
                //推送失败,重试3次
                if(stringR.getCode() != Constants.SUCCESS){
                if (stringR.getCode() != Constants.SUCCESS) {
                    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
                    executor.execute(() -> {
                        for (int i = 0; i < 3; i++) {
                            R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                            if(stringR1.getCode() == Constants.SUCCESS){
                            if (stringR1.getCode() == Constants.SUCCESS) {
                                break;
                            }
                            try {
@@ -2140,15 +2180,15 @@
                //判断是否有连环单
                String json = redisService.getCacheObject(CacheConstants.nextOrder(xpOrder.getId().toString()));
                if (StringUtils.isNotEmpty(json)){
                if (StringUtils.isNotEmpty(json)) {
                    JSONObject jsonObject = JSON.parseObject(json);
                    Long id = jsonObject.getLong("orderId");
                    jobMaps = new ImmutableMap.Builder<String, String>()
                                    .put("id", id.toString())
                                    .put("oldOrderId", xpOrder.getId().toString())
                                    .put("appid", appid)
                                    .put("orderType", OrderType.USER_ORDER)
                                    .build();
                            .put("id", id.toString())
                            .put("oldOrderId", xpOrder.getId().toString())
                            .put("appid", appid)
                            .put("orderType", OrderType.USER_ORDER)
                            .build();
                    QuartzManager.addJob(
                            PushChainReactionOrderJob.class,
@@ -2173,17 +2213,16 @@
        xpOrder.setStatus(status);
        xpOrder.setAppUserId(null);
        this.updateById(xpOrder);
        bootCommonService.setCache_orderStatus(xpOrder.getId(),xpOrder,null);
        bootCommonService.setCache_orderStatus(xpOrder.getId(), xpOrder, null);
        return R.ok();
    }
    /**
     * 行驶中车辆异常,订单状态修改- 修改状态=7 再修改 金额-再将状态修改成8
     */
    @Override
    public R<String> carAbnormalUpdateOrderStatus(Long orderId){
    public R<String> carAbnormalUpdateOrderStatus(Long orderId) {
        XpOrder xpOrder = this.getById(orderId);
        if (Objects.isNull(xpOrder)) {
            return R.fail("订单不存在");
@@ -2191,7 +2230,7 @@
        if (xpOrder.getStatus() == 0) {
            return R.fail("订单已取消");
        }
        if(xpOrder.getStatus() >= 8){
        if (xpOrder.getStatus() >= 8) {
            return R.fail("订单已结束");
        }
        // 查询车辆
@@ -2201,9 +2240,9 @@
        xpOrder.setGetoffTime(LocalDateTime.now());
        // 解析下车地点
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
        if(Objects.nonNull(vehiclePosition)){
        if (Objects.nonNull(vehiclePosition)) {
            GeoJsonPoint point = vehiclePosition.getPoint();
            if(Objects.nonNull(point)){
            if (Objects.nonNull(point)) {
                double x = point.getX();
                double y = point.getY();
                Map<String, String> geocode = gdMapGeocodingUtil.geocode(String.valueOf(x), String.valueOf(y));
@@ -2220,8 +2259,8 @@
        xpOrder.setStatus(OrderStatusEnum.SEE_OFF_GUESTS.getCode());//待客下车
        xpOrder.setAppUserId(null);
        this.updateById(xpOrder);
         //结束行程,修改状态和计算费用
        this.endTrip(xpOrder.getId(),appUserId.toString());
        //结束行程,修改状态和计算费用
        this.endTrip(xpOrder.getId(), appUserId.toString());
        //将支付金额修改成0 并将状态修改成 订单状态9
        setFree(xpOrder.getId());
@@ -2231,20 +2270,19 @@
    /**
     * 豁免
     */
    public void setFree(Long id){
    public void setFree(Long id) {
        //将支付金额修改成0 并将状态修改成 订单状态9
        XpOrder xpOrder1 = new XpOrder();
        xpOrder1.setId(id);
        xpOrder1.setIsFree( true);//豁免
        xpOrder1.setIsFree(true);//豁免
        xpOrder1.setPayMoney(BigDecimal.ZERO);
        xpOrder1.setStatus(OrderStatusEnum.PENDING_PAYMENT.getCode());
        xpOrder1.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(xpOrder1);
        bootCommonService.setCache_orderStatus(xpOrder1.getId(),xpOrder1,null);
        bootCommonService.setCache_orderStatus(xpOrder1.getId(), xpOrder1, null);
    }
    @Override
@@ -2272,7 +2310,7 @@
        order.setTripEnd(LocalDateTime.now());
        baseMapper.updateById(order);
        order.setAppUserId(appUserId);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        bootCommonService.setCache_orderStatus(order.getId(), order, null);
        //删除蓝牙秘钥
//        String token = redisService.getCacheObject("rt:bluetooth:unlock:order:" + orderId);
//        if(StringUtils.isNotBlank(token)){
@@ -2289,7 +2327,7 @@
//        }
        // 根据订单所属开通城市id 查询定价
        XpPricing pricing = bootCommonService.getXpPricing(order.getCityId(),order.getVehicleId());
        XpPricing pricing = bootCommonService.getXpPricing(order.getCityId(), order.getVehicleId());
        if (pricing == null) {
            throw new ServiceException("当前城市未配置定价规则", I18nKeyConstant.ORDER_PRICING_NOT_EXISTS);
        }
@@ -2341,10 +2379,10 @@
            xpOrderDetail.setDetailType(2);
            xpOrderDetail.setOrderId(orderId);
            xpOrderDetail.setType(1);
            xpOrderDetail.setMoney(new BigDecimal(xpPricingCardVo.getDistancePrice()).setScale(2,RoundingMode.HALF_UP));
            xpOrderDetail.setMoney(new BigDecimal(xpPricingCardVo.getDistancePrice()).setScale(2, RoundingMode.HALF_UP));
            xpOrderDetails.add(xpOrderDetail);
            //时长费不是必填项
            if(null != xpPricingCardVo.getDurationPrice() && xpPricingCardVo.getDurationPrice() > 0){
            if (null != xpPricingCardVo.getDurationPrice() && xpPricingCardVo.getDurationPrice() > 0) {
                xpOrderDetail = new XpOrderDetail();
                xpOrderDetail.setDetailType(3);
                xpOrderDetail.setOrderId(orderId);
@@ -2353,7 +2391,7 @@
                xpOrderDetails.add(xpOrderDetail);
            }
            BigDecimal totalPrice =BigDecimal.ZERO;
            BigDecimal totalPrice = BigDecimal.ZERO;
            for (XpOrderDetail xpOrderDetail1 : xpOrderDetails) {
                totalPrice = totalPrice.add(xpOrderDetail1.getMoney());
                xpOrderDetailMapper.insert(xpOrderDetail1);
@@ -2361,8 +2399,7 @@
            order.setOrderMoney(totalPrice);
            order.setAppUserId(null);
            baseMapper.updateById(order);
        }
        else {
        } else {
            //动态计费
            if (pricing.getPricingType() == 1) {
                for (int i = 0; i < startingFareJsonArray.size(); i++) {
@@ -2454,14 +2491,14 @@
                            // 天气预报动态调价
                            JSONArray ws = jsonObject.getJSONArray("weather");
                            if(null != ws){
                            if (null != ws) {
                                WeatherDTO data = xpMapClient.wether(order.getCityCode()).getData();
                                List<WeatherDTO.Lives> lives = data.getLives();
                                if(lives!=null && !lives.isEmpty()){
                                if (lives != null && !lives.isEmpty()) {
                                    String w = lives.get(0).getWeather();
                                    for (Object o : ws) {
                                        JSONObject ele = JSONObject.parseObject(o.toString());
                                        if(w.contains(ele.getString("weatherType"))){
                                        if (w.contains(ele.getString("weatherType"))) {
                                            double floatRate = jsonObject.getDouble("ratio");
                                            priceRate = new BigDecimal(priceRate).add(new BigDecimal(floatRate)).doubleValue();
                                            break;
@@ -2550,16 +2587,16 @@
                // 封装时长费
                FareBreakdownDetailVo timeDetail = new FareBreakdownDetailVo();
                if (key.contains("时长费")) {
                    if(key.contains("普通时段")){
                    if (key.contains("普通时段")) {
                        timeDetail.setType(1);
                    }
                    if(key.contains("夜间行驶")){
                    if (key.contains("夜间行驶")) {
                        timeDetail.setType(2);
                    }
                    if(key.contains("高峰")){
                    if (key.contains("高峰")) {
                        timeDetail.setType(3);
                    }
                    if(key.contains("节假")){
                    if (key.contains("节假")) {
                        timeDetail.setType(4);
                    }
@@ -2661,17 +2698,17 @@
        UserCouponVo userCouponVo = userCouponVoR.getData();
        // 提示是否换券
        boolean tip =false;
        boolean tip = false;
        if (userCouponVo != null) {
            // 重新选券
            if(userCouponVo.getStatus()==2){
            if (userCouponVo.getStatus() == 2) {
                getUserCouponDto.setUserId(Long.valueOf(uid));
                getUserCouponDto.setTotalAmount(order.getOrderMoney().doubleValue());
                getUserCouponDto.setUserCouponId(order.getCouponId());
                getUserCouponDto.setOpenCityId(order.getCityId());
                userCouponVoR = xpAppUserCouponClient.getUserCoupon(getUserCouponDto);
                userCouponVo = userCouponVoR.getData();
                tip=true;
                tip = true;
            }
            order.setCouponId(userCouponVo.getId());
            order.setCouponMoney(BigDecimal.valueOf(userCouponVo.getMoney()));
@@ -2726,11 +2763,11 @@
        xpCruiseOrder.setXpuTaskId(snowflake.nextId() + "");
        // 完成的直接走终点   终止的走起点
        if(null != xpCruiseOrders){
        if (null != xpCruiseOrders) {
            if (temp == 0) {
                //当上一笔单有起点点位,才需要将上一笔巡游单的起点作为本次的终点导航
                //上一笔单没有起点点位,统一用后面的巡游计划的第一个点位作为本次的终点导航
                if(null != xpCruiseOrders.getStartPointId()){
                if (null != xpCruiseOrders.getStartPointId()) {
                    xpCruiseOrder.setEndPointId(xpCruiseOrders.getStartPointId());
                    xpCruiseOrder.setEndPointName(xpCruiseOrders.getStartPointName());
                    xpCruiseOrder.setEndLon(xpCruiseOrders.getStartLon());
@@ -2747,7 +2784,7 @@
            xpCruiseOrder.setMissionId(xpCruiseOrders.getMissionId());
        }
        //所有没有赋值终点点位的情况,全部导航到巡游计划的第一个点位开始执行巡游任务
        if(null == xpCruiseOrder.getEndPointId()){
        if (null == xpCruiseOrder.getEndPointId()) {
            // 先找计划
            List<XpCruisePlanPoint> planPointList = xpCruisePlanClient.getCruisePlanPointList(vehicle.getId()).getData();
            XpCruisePlanPoint xpCruisePlanPoint = planPointList.get(0);
@@ -2764,7 +2801,7 @@
        xpCruiseOrder.setCreateTime(LocalDateTime.now());
        // 判断当前时分秒是否大于收车时间&&收车配置开启
        if(null != xpTaskRule && xpTaskRule.getVehicleCollection()){
        if (null != xpTaskRule && xpTaskRule.getVehicleCollection()) {
            LocalTime vehicleCollectionTime = xpTaskRule.getVehicleCollectionTime();
            if (vehicleCollectionTime.isBefore(LocalTime.now())) {
                XpVehicle vehicle1 = new XpVehicle();
@@ -2773,7 +2810,7 @@
                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);
@@ -2842,11 +2879,11 @@
        xpCruiseOrder.setStartLat(vehiclePosition.getPoint().getY());
        // 完成的直接走终点   终止的走起点
        if(null != xpCruiseOrders){
        if (null != xpCruiseOrders) {
            if (temp == 0) {
                //当上一笔单有起点点位,才需要将上一笔巡游单的起点作为本次的终点导航
                //上一笔单没有起点点位,统一用后面的巡游计划的第一个点位作为本次的终点导航
                if(null != xpCruiseOrders.getStartPointId()){
                if (null != xpCruiseOrders.getStartPointId()) {
                    xpCruiseOrder.setEndPointId(xpCruiseOrders.getStartPointId());
                    xpCruiseOrder.setEndPointName(xpCruiseOrders.getStartPointName());
                    xpCruiseOrder.setEndLon(xpCruiseOrders.getStartLon());
@@ -2863,7 +2900,7 @@
            xpCruiseOrder.setMissionId(xpCruiseOrders.getMissionId());
        }
        //所有没有赋值终点点位的情况,全部导航到巡游计划的第一个点位开始执行巡游任务
        if(null == xpCruiseOrder.getEndPointId()){
        if (null == xpCruiseOrder.getEndPointId()) {
            // 先找计划
            List<XpCruisePlanPoint> planPointList = xpCruisePlanClient.getCruisePlanPointList(vehicle.getId()).getData();
            XpCruisePlanPoint xpCruisePlanPoint = planPointList.get(0);
@@ -2882,7 +2919,7 @@
        xpCruiseOrder.setCreateTime(LocalDateTime.now());
        // 判断当前时分秒是否大于收车时间&&收车配置开启
        if(null != xpTaskRule && xpTaskRule.getVehicleCollection()){
        if (null != xpTaskRule && xpTaskRule.getVehicleCollection()) {
            LocalTime vehicleCollectionTime = xpTaskRule.getVehicleCollectionTime();
            if (vehicleCollectionTime.isBefore(LocalTime.now())) {
                XpVehicle vehicle1 = new XpVehicle();
@@ -2891,7 +2928,7 @@
                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);
@@ -3121,7 +3158,7 @@
    public R<FareBreakdownVo> fareBreakdown(com.xiaopeng.order.vo.FareBreakdownVo vo, String uid) {
        XpOrder order = this.getById(vo.getOrderId());
        //根据新的优惠券计算优惠金额
        if(null != order.getCouponId()){
        if (null != order.getCouponId()) {
            CalculateDiscountAmountVo discountAmountVo = new CalculateDiscountAmountVo();
            BigDecimal data = xpAppUserCouponClient.calculateDiscountAmount(discountAmountVo).getData();
            order.setCouponId(vo.getUserCouponId());
@@ -3142,15 +3179,15 @@
            detail.setType(xpOrderDetail.getType());
            detail.setTime(xpOrderDetail.getTime());
            detail.setMileage(xpOrderDetail.getMileage());
            detail.setDuration((xpOrderDetail.getDuration() == null ? 0 : xpOrderDetail.getDuration())*60);
            detail.setDuration((xpOrderDetail.getDuration() == null ? 0 : xpOrderDetail.getDuration()) * 60);
            detail.setMoney(xpOrderDetail.getMoney());
            if (xpOrderDetail.getDetailType() == 1) {
                start.add(detail);
            } else if(xpOrderDetail.getDetailType()==2){
            } else if (xpOrderDetail.getDetailType() == 2) {
                mileage.add(detail);
            }else if(xpOrderDetail.getDetailType()==3){
            } else if (xpOrderDetail.getDetailType() == 3) {
                duration.add(detail);
            }else if(xpOrderDetail.getDetailType()==4){
            } else if (xpOrderDetail.getDetailType() == 4) {
                longDistance.add(detail);
            }
        }
@@ -3173,12 +3210,11 @@
        }
        res.setTime(new BigDecimal(order.getDuration() == null ? 0 : order.getDuration()).multiply(new BigDecimal(60)).setScale(0, RoundingMode.HALF_UP));
        XpSystemSetting xpSystemSetting = xpSystemSettingClient.getSystemSettingOne().getData();
        if(null != xpSystemSetting){
        if (null != xpSystemSetting) {
            res.setOperateFree(xpSystemSetting.getOperateFree());
        }
        return R.ok(res);
    }
    @Override
@@ -3187,22 +3223,22 @@
        XpOrder order = this.getById(dto.getOrderId());
        order.setStatus(9);
        order.setAppUserId(null);
        if(order.getCouponId()!=null){
        if (order.getCouponId() != null) {
            UseUserCouponDto useUserCouponDto = new UseUserCouponDto();
            useUserCouponDto.setUserCouponId(order.getCouponId());
            R<BigDecimal> decimalR = xpAppUserCouponClient.useUserCoupon(useUserCouponDto);
            if(decimalR.getCode()==200){
            if (decimalR.getCode() == 200) {
                order.setCouponMoney(decimalR.getData());
                if(order.getCouponMoney().compareTo(order.getOrderMoney())>0){
                if (order.getCouponMoney().compareTo(order.getOrderMoney()) > 0) {
                    order.setPayMoney(BigDecimal.ZERO);
                    order.setCouponMoney(order.getOrderMoney());
                }else {
                } else {
                    order.setPayMoney(order.getOrderMoney().subtract(decimalR.getData()));
                }
            }
        }
        baseMapper.updateById(order);
        bootCommonService.setCache_orderStatus(order.getId(),order,null);
        bootCommonService.setCache_orderStatus(order.getId(), order, null);
        return R.ok();
    }
@@ -3256,7 +3292,7 @@
    public void saveVehicleLocation(OrderTrajectory orderTrajectory) {
        // 查询订单信息
        Integer status = redisService.getCacheObject("ORDER_STATUS:" + orderTrajectory.getOrderId());
        if(status < 6 || status > 8){
        if (status < 6 || status > 8) {
            return;
        }
@@ -3448,18 +3484,18 @@
                vehicleEventDTO.setOrderId(String.valueOf(dto.getOrderId()));
                vehicleEventDTO.setEventKey("RT_xpu_vehicle_trace_upload");
                vehicleEventDTO.setEventTime(System.currentTimeMillis());
                Map<String,Object> attributes = new HashMap<>();
                attributes.put("vin",vehicleEventDTO.getVin());
                attributes.put("order_id",vehicleEventDTO.getOrderId());
                attributes.put("order_type","cruise_order");
                attributes.put("timestamp",vehicleEventDTO.getEventTime());
                Map<String, Object> attributes = new HashMap<>();
                attributes.put("vin", vehicleEventDTO.getVin());
                attributes.put("order_id", vehicleEventDTO.getOrderId());
                attributes.put("order_type", "cruise_order");
                attributes.put("timestamp", vehicleEventDTO.getEventTime());
                attributes.put("current_main_status", OrderStatus.ORDER_STARTED);
                attributes.put("current_sub_status","");
                attributes.put("current_sub_status", "");
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(dto.getXpVehicleVin())), VehiclePosition.class);
                if(Objects.nonNull(vehiclePosition)){
                    attributes.put("odometer_km",vehiclePosition.getTotalOdometer());
                }else {
                    attributes.put("odometer_km","");
                if (Objects.nonNull(vehiclePosition)) {
                    attributes.put("odometer_km", vehiclePosition.getTotalOdometer());
                } else {
                    attributes.put("odometer_km", "");
                }
                vehicleEventDTO.setAttributes(attributes);
                vehicleBuriedPointClient.sendVehicleEvent(vehicleEventDTO);
@@ -3506,7 +3542,7 @@
                addTaxiPassengerVo.setUid(appUserId.toString());
                order.setAppUserId(null);
                this.updateById(order);
                bootCommonService.setCache_orderStatus(order.getId(),order,null);
                bootCommonService.setCache_orderStatus(order.getId(), order, null);
                //构建推送消息
                Map<String, Object> params = new HashMap<>();
@@ -3523,12 +3559,12 @@
                R<String> stringR = xpPushMessageClient.sendStatus(dto1);
                //推送失败,重试3次
                if(stringR.getCode() != Constants.SUCCESS){
                if (stringR.getCode() != Constants.SUCCESS) {
                    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
                    executor.execute(() -> {
                        for (int i = 0; i < 3; i++) {
                            R<String> stringR1 = xpPushMessageClient.sendStatus(dto1);
                            if(stringR1.getCode() == Constants.SUCCESS){
                            if (stringR1.getCode() == Constants.SUCCESS) {
                                break;
                            }
                            try {
@@ -3620,7 +3656,7 @@
//                log.info("下发蓝牙token成功:{} {}", deliver.getData(), order.getOrderNumber());
            }
            if(order.getStatus() == 2){
            if (order.getStatus() == 2) {
                // 封装埋点消息实体
                VehicleEventDTO vehicleEventDTO = new VehicleEventDTO();
                vehicleEventDTO.setVin(dto.getXpVehicleVin());
@@ -3628,18 +3664,18 @@
                vehicleEventDTO.setOrderId(String.valueOf(dto.getOrderId()));
                vehicleEventDTO.setEventKey("RT_xpu_vehicle_trace_upload");
                vehicleEventDTO.setEventTime(System.currentTimeMillis());
                Map<String,Object> attributes = new HashMap<>();
                attributes.put("vin",vehicleEventDTO.getVin());
                attributes.put("order_id",vehicleEventDTO.getOrderId());
                attributes.put("order_type","user_order");
                attributes.put("timestamp",vehicleEventDTO.getEventTime());
                attributes.put("current_main_status",OrderStatus.ORDER_EN_ROUTE_TO_PICKUP);
                attributes.put("current_sub_status","");
                Map<String, Object> attributes = new HashMap<>();
                attributes.put("vin", vehicleEventDTO.getVin());
                attributes.put("order_id", vehicleEventDTO.getOrderId());
                attributes.put("order_type", "user_order");
                attributes.put("timestamp", vehicleEventDTO.getEventTime());
                attributes.put("current_main_status", OrderStatus.ORDER_EN_ROUTE_TO_PICKUP);
                attributes.put("current_sub_status", "");
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(dto.getXpVehicleVin())), VehiclePosition.class);
                if(Objects.nonNull(vehiclePosition)){
                    attributes.put("odometer_km",vehiclePosition.getTotalOdometer());
                }else {
                    attributes.put("odometer_km","");
                if (Objects.nonNull(vehiclePosition)) {
                    attributes.put("odometer_km", vehiclePosition.getTotalOdometer());
                } else {
                    attributes.put("odometer_km", "");
                }
                vehicleEventDTO.setAttributes(attributes);
                vehicleBuriedPointClient.sendVehicleEvent(vehicleEventDTO);
@@ -3734,12 +3770,12 @@
            R<String> stringR = xpPushMessageClient.sendRoute(messageDTO);
            XpOrder xpOrder = this.getById(orderId);
            //推送失败,重试3次
            if(stringR.getCode() != Constants.SUCCESS){
            if (stringR.getCode() != Constants.SUCCESS) {
                ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
                executor.execute(() -> {
                    for (int i = 0; i < 3; i++) {
                        R<String> stringR1 = xpPushMessageClient.sendStatus(messageDTO);
                        if(stringR1.getCode() == Constants.SUCCESS){
                        if (stringR1.getCode() == Constants.SUCCESS) {
                            break;
                        }
                        try {
@@ -3802,7 +3838,7 @@
            xpOrderDetailVO.setVehiclePictures(vehicle.getVehiclePictures());
        }
        Integer status = xpOrder.getStatus();
        if(status > 2 && status < 8){
        if (status > 2 && status < 8) {
//            Boolean data = xpVehicleClient.getVehicleTrunkOpenStatus(xpOrder.getAppUserId(), xpOrder.getVehicleId()).getData();
//            xpOrder.setOpenTrunk(data ? 1 : 2);
//            xpOrderDetailVO.setOpenTrunk(data ? 1 : 2);
@@ -3815,7 +3851,7 @@
    }
    @Override
    public XpOrderDetailVO getActiveOrder_itineraryManage(String uid){
    public XpOrderDetailVO getActiveOrder_itineraryManage(String uid) {
        XpOrderDetailVO xpOrderDetailVO = new XpOrderDetailVO();
        XpOrder xpOrder = this.baseMapper.selectOne(new LambdaQueryWrapper<XpOrder>().eq(XpOrder::getAppUserId, Long.parseLong(uid)).in(XpOrder::getStatus, Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8)).orderByDesc(BaseModel::getCreateTime).last("LIMIT 1"));
        if (xpOrder == null) {
@@ -3832,24 +3868,26 @@
            xpOrderDetailVO.setVehiclePictures(vehicle.getVehiclePictures());
        }
        Boolean cancelShow = isCancelShow(xpOrder,xpOrderDetailVO.getVehicleVin()); //是否能取消行程
        Boolean cancelShow = isCancelShow(xpOrder, xpOrderDetailVO.getVehicleVin()); //是否能取消行程
        xpOrderDetailVO.setCancelShow(cancelShow);
        return xpOrderDetailVO;
    }
    /**
     * 取消行程:若处于“送驾中”且离目的地小于10分钟路程(后台配置),【取消行程】按钮应置灰;
     * 修改行程:
     * 1. 当前剩余里程 < 800米 (后台配置)或 剩余时间 < 5分钟(后台配置)(以先到者为准),禁止修改,按钮置灰。
     * 2. 单次行程最多允许修改 2次 (后台配置)目的地,防恶意高频调用
     * 特殊豁免:若系统检测到车辆在当前坐标时速 < 3km/h 且持续时间 > 3分钟(后台配置)(判定为极度拥堵或异常停滞),此时解除限制,允许用户修改目的地或新增途径点以寻找更近的下车位置。
     *
     * @return
     */
    private boolean isCancelShow(XpOrder xpOrder,String vehicleVin) {
    private boolean isCancelShow(XpOrder xpOrder, String vehicleVin) {
        boolean isCancel = false;
        //获取系统配置
        XpSystemSetting systemSetting = xpSystemSettingClient.getSystemSettingOne().getData();
        if(systemSetting == null){
        if (systemSetting == null) {
            throw new ServiceException("获取行程配置错误");
        }
        //获取配置文件
@@ -3861,17 +3899,17 @@
        List<OrderTrajectory> orderTrajectories = queryOrderTrajectories(xpOrder.getId());
        if(!orderTrajectories.isEmpty()){// 减少3分钟 获取3分账内的 行程数据
        if (!orderTrajectories.isEmpty()) {// 减少3分钟 获取3分账内的 行程数据
            //3千米/小时 转换成分钟 50米/分钟
            BigDecimal suduDefault = new BigDecimal(xczSpeedPerHour);//3千米/小时
            BigDecimal suduDefault1 = suduDefault.multiply(BigDecimal.valueOf(1000)) ;
            BigDecimal suduDefaultNew =suduDefault1.divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_EVEN);
            BigDecimal suduDefault1 = suduDefault.multiply(BigDecimal.valueOf(1000));
            BigDecimal suduDefaultNew = suduDefault1.divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_EVEN);
            LocalDateTime minutesBefore = LocalDateTime.now().minusMinutes(xczHmDuration);
            long milliseconds = DateUtils.getMilliseconds(minutesBefore);
            List<OrderTrajectory> orderTrajectoriesNew = new ArrayList<>();
            for (OrderTrajectory orderTrajectory : orderTrajectories) {
                if(orderTrajectory.getLocatetime() > milliseconds){
                if (orderTrajectory.getLocatetime() > milliseconds) {
                    orderTrajectoriesNew.add(orderTrajectory);
                }
            }
@@ -3880,24 +3918,24 @@
             */
            //计算行驶总距离和时长
            Double reduce = orderTrajectoriesNew.stream().map(OrderTrajectory::getDistance).reduce(0.0, Double::sum);
            BigDecimal xcsudu = new BigDecimal(reduce).divide(new BigDecimal(xczHmDuration),2, RoundingMode.HALF_EVEN);//米/分钟
            BigDecimal xcsudu = new BigDecimal(reduce).divide(new BigDecimal(xczHmDuration), 2, RoundingMode.HALF_EVEN);//米/分钟
            //特殊豁免:若系统检测到车辆在当前坐标时速 < 3km/h 且持续时间 > 3分钟(后台配置)(判定为极度拥堵或异常停滞),此时解除限制,允许用户修改目的地或新增途径点以寻找更近的下车位置。
            if(xcsudu.compareTo(suduDefaultNew)<0){
            if (xcsudu.compareTo(suduDefaultNew) < 0) {
                return true;
            }
        }
        try {
            RouteVo routeVo = this.getRouteVo(xpOrder, vehicleVin);
            if(routeVo.getDistance() <sylc){
            if (routeVo.getDistance() < sylc) {
                isCancel = true;
            }
            if(routeVo.getDuration() < sysj){
            if (routeVo.getDuration() < sysj) {
                isCancel = true;
            }
        } catch (Exception e) {
            log.error("获取两个点位车的距离错误",e);
            log.error("获取两个点位车的距离错误", e);
            throw new ServiceException("获取两个点位车的距离错误");
        }
@@ -3907,11 +3945,12 @@
    /**
     * 获取两个点位车的距离 和时间
     *
     * @param xpOrder
     * @param vehicleVin
     * @return
     */
    private RouteVo getRouteVo(XpOrder xpOrder,String vehicleVin){
    private RouteVo getRouteVo(XpOrder xpOrder, String vehicleVin) {
        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(vehicleVin)), VehiclePosition.class);
        // 计算距离 和 时间
@@ -3933,7 +3972,7 @@
            routeAndFareDto.setRoutePlanRule(xpRoutePlan.getRoutePlanRule());
        }
        R<RouteVo> distanceAndDuration = xpMapClient.getDistanceAndDuration(routeAndFareDto);
        if(distanceAndDuration.getCode()!=200){
        if (distanceAndDuration.getCode() != 200) {
            throw new ServiceException("未找到路径", I18nKeyConstant.PATH_NOT_FOUND);
        }
        return distanceAndDuration.getData();
@@ -3993,12 +4032,12 @@
        sendMessageDTO.setAppUserId(String.valueOf(appUserId));
        R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
        //推送失败,重试3次
        if(stringR.getCode() != Constants.SUCCESS){
        if (stringR.getCode() != Constants.SUCCESS) {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                    if(stringR1.getCode() == Constants.SUCCESS){
                    if (stringR1.getCode() == Constants.SUCCESS) {
                        break;
                    }
                    try {
@@ -4016,6 +4055,7 @@
    /**
     * 获取待支付订单数量
     *
     * @param uid
     * @return
     */
@@ -4032,6 +4072,7 @@
    /**
     * 根据 UID 查询用户是否有 RT 订单 & 订单列表
     *
     * @param dto
     * @return
     */
@@ -4062,6 +4103,7 @@
    /**
     * 获取订单详情
     *
     * @param orderId
     * @return
     */
@@ -4076,13 +4118,13 @@
        XpPoint endPoint = xpPointClient.queryById(xpOrder.getEndPointId()).getData();
        vo.setDestAddress(endPoint.getPointAddress());
        vo.setPullOverAddress(xpOrder.getGetoffAddress());
        if(null != xpOrder.getEstimatedArrivalTime()){
        if (null != xpOrder.getEstimatedArrivalTime()) {
            vo.setEstimatedArrivalTime(xpOrder.getEstimatedArrivalTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
        if(null != xpOrder.getGetoffTime()){
        if (null != xpOrder.getGetoffTime()) {
            vo.setActualArrivalTime(xpOrder.getGetoffTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
        if(null == xpOrder.getMileageKilometers()){
        if (null == xpOrder.getMileageKilometers()) {
            vo.setActualMileage(BigDecimal.valueOf(xpOrder.getMileageKilometers()));
        }
        vo.setTotalPrice(xpOrder.getOrderMoney());
@@ -4094,11 +4136,11 @@
        vo.setCouponDiscount(xpOrder.getCouponMoney());
        vo.setActualPayment(xpOrder.getPayMoney());
        XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
        if(null != xpVehicle){
        if (null != xpVehicle) {
            vo.setVin(xpVehicle.getVehicleVin());
        }
        XpOrderCancel orderCancel = xpOrderCancelService.getOne(new QueryWrapper<XpOrderCancel>().eq("order_id", orderId));
        if(null != orderCancel){
        if (null != orderCancel) {
            vo.setCancelReasonType(orderCancel.getCancelReason());
        }
        return vo;
@@ -4108,10 +4150,337 @@
    /**
     *
     * 合作商更新订单状态
     *
     * @param vo
     */
    @Override
    public void officialPartnerUpdateOrderStatus(UpdateOrderStatusVo vo) {
    public R<?> officialPartnerUpdateOrderStatus(UpdateOrderStatusVo vo, Integer officialPartnerId) {
        XpOrder xpOrder = this.getOne(new QueryWrapper<XpOrder>().eq("order_number", vo.getOrderNum()));
        if (null == xpOrder) {
            return R.fail("无效的订单编号");
        }
        if (xpOrder.getStatus() >= 8) {
            return R.fail("订单已结束,无法修改");
        }
        switch (vo.getOrderStatus()) {
            case 2:
                if (xpOrder.getStatus() != 1) {
                    return R.fail("订单状态不允许改为已接单");
                }
                if (StringUtils.isEmpty(vo.getVehiclePlateNumber())) {
                    return R.fail("车牌号不能为空");
                }
                if (null == vo.getAcceptanceTime()) {
                    return R.fail("接单时间不能为空");
                }
                XpVehicle xpVehicle = xpVehicleClient.getVehicleByPlateNumber(vo.getVehiclePlateNumber(), officialPartnerId).getData();
                if (null == xpVehicle) {
                    return R.fail("车牌号不存在");
                }
                xpOrder.setOfficialPartnerId(officialPartnerId);
                xpOrder.setVehicleId(xpVehicle.getId());
                xpOrder.setAcceptanceTime(vo.getAcceptanceTime());
                redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), OrderStatusEnum.READY_DEPART.getCode(), 24L, TimeUnit.HOURS);
                //将订单弹出队列
                try {
                    redisService.popFirstElement(xpOrder.getQueueName());
                } catch (Exception e) {
                    log.error("Redis弹出队列元素出错");
                }
                // 存mongo数据
                xpPricingClient.updateXpGeoQueryEntity(xpOrder.getId().toString());
                bootCommonService.setCache_orderStatus(xpOrder.getId(), xpOrder, null);
                //生成前往上车点的导航数据
                //查询车辆位置
                VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
                if (Objects.isNull(vehiclePosition)) {
                    throw new RuntimeException("车辆位置信息不存在");
                }
                LonLatDto destination = new LonLatDto();
                LonLatDto origin = new LonLatDto();
                //查询司机当前位置到起点的线路
                origin.setLongitude(vehiclePosition.getPoint().getX());
                origin.setLatitude(vehiclePosition.getPoint().getY());
                destination.setLongitude(xpOrder.getStartLon());
                destination.setLatitude(xpOrder.getStartLat());
                OrderRouteAndFareDto dto2 = new OrderRouteAndFareDto();
                dto2.setOrderId(xpOrder.getId());
                dto2.setOrigin(origin);
                dto2.setDestination(destination);
                dto2.setRouteType(1);
                dto2.setVehicleId(xpVehicle.getId());
                R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto2);
                if (200 != routeVoR.getCode()) {
                    throw new RuntimeException("获取订单线路和运费失败");
                }
                RouteVo routeVo = routeVoR.getData();
                //缓存数据,用于后续推给乘客导航线路
                redisService.setCacheObject("ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId(), JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
                //推送乘客车辆到达预约点的导航数据
                sendRoute(xpOrder.getAppUserId() + "", xpOrder.getId(), "ORDER_NAVIGATION_START_DATA", xpVehicle.getVehicleVin());
                break;
            case 3:
                if (xpOrder.getStatus() != 2) {
                    return R.fail("订单状态不允许改为接驾中");
                }
                if (null == vo.getTripBegin()) {
                    return R.fail("行程开始时间不能为空");
                }
                xpOrder.setTripBegin(vo.getTripBegin());
                redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), OrderStatusEnum.PICK_UP.getCode(), 24L, TimeUnit.HOURS);
                break;
            case 4:
                if (xpOrder.getStatus() != 3) {
                    return R.fail("订单状态不允许改为到达上车点");
                }
                if (null == vo.getArrivalTime()) {
                    return R.fail("车辆到达上车点时间不能为空");
                }
                // 查询起点点位
                Long startPointId = xpOrder.getStartPointId();
                XpPoint xpPoint = xpPointClient.queryById(startPointId).getData();
                // 添加取消订单定时任务job  时间为点位限停时长
                Map<String, ? extends Object> cancelJobMaps =
                        new ImmutableMap.Builder<String, Long>().
                                put("id", xpOrder.getId())
                                .build();
                QuartzManager.addJob(
                        OrderCancelJob.class,
                        (OrderCancelJob.name + xpOrder.getId()).toUpperCase(),
                        TimeJobType.ORDER_CANCEL,
                        DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(xpPoint.getParkingTimeLimit())),
                        cancelJobMaps
                );
                xpOrder.setArrivalTime(vo.getArrivalTime());
                redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), OrderStatusEnum.PICK_UP_GUESTS.getCode(), 24L, TimeUnit.HOURS);
                break;
            case 5:
                if (xpOrder.getStatus() != 4) {
                    return R.fail("订单状态不允许改为乘客已上车");
                }
                if (null == vo.getBoardingLon()) {
                    return R.fail("上车点经度不能为空");
                }
                if (null == vo.getBoardingLat()) {
                    return R.fail("上车点纬度不能为空");
                }
                if (StringUtils.isEmpty(vo.getBoardingAddress())) {
                    return R.fail("上车点地址不能为空");
                }
                if (null == vo.getBoardingTime()) {
                    return R.fail("上车时间不能为空");
                }
                xpOrder.setBoardingLon(vo.getBoardingLon());
                xpOrder.setBoardingLat(vo.getBoardingLat());
                xpOrder.setBoardingAddress(vo.getBoardingAddress());
                xpOrder.setBoardingTime(vo.getBoardingTime());
                xpOrder.setRideTime(vo.getBoardingTime());
                redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), OrderStatusEnum.PASSENGER_BOARDED.getCode(), 24L, TimeUnit.HOURS);
                XpVehicle xpVehicle1 = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
                //推送行起点到终点的驶轨迹给乘客端
                sendRoute(xpOrder.getAppUserId() + "", xpOrder.getId(), "ORDER_NAVIGATION_END_DATA", xpVehicle1.getVehicleVin());
                // 删除定时任务job
                QuartzManager.removeJob((OrderCancelJob.name + xpOrder.getId()).toUpperCase(), TimeJobType.ORDER_CANCEL);
                //乘客已上车,重新倒计时不开始行程取消订单
                XpPoint xpPoint1 = xpPointClient.queryById(xpOrder.getStartPointId()).getData();
                XpTradingStrategy tradingStrategy = tradingStrategyClient.getTradingStrategyByCityCode(xpPoint1.getCityCode()).getData();
                if (null != tradingStrategy) {
                    Map<String, ? extends Object> cancelJobMaps1 =
                            new ImmutableMap.Builder<String, Long>().
                                    put("id", xpOrder.getId())
                                    .build();
                    QuartzManager.addJob(
                            OrderCancelJob.class,
                            (OrderCancelJob.name + xpOrder.getId()).toUpperCase(),
                            TimeJobType.ORDER_CANCEL,
                            DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(tradingStrategy.getBdNotBoardedTime())),
                            cancelJobMaps1
                    );
                }
                break;
            case 6:
                if (xpOrder.getStatus() != 5) {
                    return R.fail("订单状态不允许改为服务中");
                }
                // 删除定时任务job
                QuartzManager.removeJob((OrderCancelJob.name + xpOrder.getId()).toUpperCase(), TimeJobType.ORDER_CANCEL);
                xpOrder.setTripBegin(vo.getTripBegin());
                redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), OrderStatusEnum.IN_SERVICE.getCode(), 24L, TimeUnit.HOURS);
                String cacheObject = redisService.getCacheObject("ORDER_NAVIGATION_END_DATA:" + xpOrder.getAppUserId());
                if (StringUtils.isNotBlank(cacheObject)) {
                    RouteVo routeVo1 = JSONObject.parseObject(cacheObject, RouteVo.class);
                    xpOrder.setEstimatedArrivalTime(LocalDateTime.now().plusSeconds(routeVo1.getDuration()));
                }
                redisService.deleteObject("ORDER_NAVIGATION_START_DATA:" + xpOrder.getAppUserId());
                break;
            case 7:
                if (xpOrder.getStatus() != 6) {
                    return R.fail("订单状态不允许改为待乘客下车");
                }
                if (null == vo.getTripEnd()) {
                    return R.fail("行程结束时间不能为空");
                }
                if (null == vo.getGetoffLon()) {
                    return R.fail("下车点经度不能为空");
                }
                if (null == vo.getGetoffLat()) {
                    return R.fail("下车点纬度不能为空");
                }
                if (StringUtils.isEmpty(vo.getGetoffAddress())) {
                    return R.fail("下车点地址不能为空");
                }
                if (null == vo.getGetoffTime()) {
                    return R.fail("下车时间不能为空");
                }
                xpOrder.setGetoffTime(vo.getGetoffTime());
                xpOrder.setGetoffLon(vo.getGetoffLon());
                xpOrder.setGetoffLat(vo.getGetoffLat());
                xpOrder.setGetoffAddress(vo.getGetoffAddress());
                xpOrder.setTripEnd(vo.getTripEnd());
                //计算行驶总距离和时长
                List<OrderTrajectory> orderTrajectoryList = mongoTemplate.find(new Query().addCriteria(Criteria.where("orderId").is(xpOrder.getId())), OrderTrajectory.class);
                Double reduce = orderTrajectoryList.stream().map(OrderTrajectory::getDistance).reduce(0.0, Double::sum);
                xpOrder.setMileageKilometers(new BigDecimal(reduce).divide(new BigDecimal(1000)).setScale(4, RoundingMode.HALF_EVEN).doubleValue());
                long duration = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - xpOrder.getTripBegin().toEpochSecond(ZoneOffset.of("+8"));
                xpOrder.setDuration(new BigDecimal(duration).divide(new BigDecimal(60), 2, RoundingMode.HALF_EVEN).doubleValue());
                // 推送倒计时消息
                Map<String, Object> params = new HashMap<>();
                Map<String, Object> content = new HashMap<>();
                content.put("orderId", xpOrder.getId().toString());
                content.put("isOpen", 1);
                params.put("type", PushMessageTypeEnum.OPEN_TRUNK.getDesc());
                params.put("content", JSONObject.toJSONString(content));
                params.put("timestamp", new Date().getTime() + "");
                String message = JSONObject.toJSONString(params);
                SendMessageDTO sendMessageDTO = new SendMessageDTO();
                sendMessageDTO.setMessage(message);
                sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId()));
                R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
                //推送失败,重试3次
                if (stringR.getCode() != Constants.SUCCESS) {
                    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
                    executor.execute(() -> {
                        for (int i = 0; i < 3; i++) {
                            R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
                            if (stringR1.getCode() == Constants.SUCCESS) {
                                break;
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            log.info("推送倒计时消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(sendMessageDTO), xpOrder.getOrderNumber());
                        }
                    });
                }
                Integer arriveTime = xpSystemSettingClient.getOrderFinishTime().getData();
                // 添加自动结束行程定时任务job
                Map<String, ? extends Object> endTripJobMaps =
                        new ImmutableMap.Builder<String, String>()
                                .put("id", xpOrder.getId().toString())
                                .put("appid", appid)
                                .put("orderType", OrderType.USER_ORDER)
                                .build();
                QuartzManager.addJob(
                        EndTripJob.class,
                        (EndTripJob.name + xpOrder.getId()).toUpperCase(),
                        TimeJobType.END_TRIP,
                        DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(arriveTime)),
                        endTripJobMaps
                );
                // 添加车辆到达终点后限停时间到后驶离的定时任务
                //时间到后将车辆状态回滚到空闲、添加巡游订单,解绑用户和车辆关系,车辆驶离点位
                XpPoint point = xpPointClient.queryById(xpOrder.getEndPointId()).getData();
                Map<String, ? extends Object> jobMaps =
                        new ImmutableMap.Builder<String, String>()
                                .put("id", xpOrder.getId().toString())
                                .put("appid", appid)
                                .put("orderType", OrderType.USER_ORDER)
                                .build();
                //判断是否有连环单
                String json = redisService.getCacheObject(CacheConstants.nextOrder(xpOrder.getId().toString()));
                if (StringUtils.isNotEmpty(json)) {
                    JSONObject jsonObject = JSON.parseObject(json);
                    Long id = jsonObject.getLong("orderId");
                    jobMaps = new ImmutableMap.Builder<String, String>()
                            .put("id", id.toString())
                            .put("oldOrderId", xpOrder.getId().toString())
                            .put("appid", appid)
                            .put("orderType", OrderType.USER_ORDER)
                            .build();
                    QuartzManager.addJob(
                            PushChainReactionOrderJob.class,
                            (PushChainReactionOrderJob.name + id).toUpperCase(),
                            TimeJobType.ADD_CHAIN_REACTION_ORDER_MISSION,
                            DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(point.getParkingTimeLimit())),
                            jobMaps
                    );
                } else {
                    QuartzManager.addJob(
                            AddCruiseMissionJob.class,
                            (AddCruiseMissionJob.name + xpOrder.getId()).toUpperCase(),
                            TimeJobType.ADD_CRUISE_MISSION,
                            DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(point.getParkingTimeLimit())),
                            jobMaps
                    );
                }
                redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), OrderStatusEnum.SEE_OFF_GUESTS.getCode(), 24L, TimeUnit.HOURS);
                break;
            default:
                return R.fail("无效的订单状态");
        }
        xpOrder.setStatus(vo.getOrderStatus());
        this.updateById(xpOrder);
        //推送订单状态给乘客端
        Map<String, Object> params = new HashMap<>();
        Map<String, Object> content = new HashMap<>();
        content.put("orderId", xpOrder.toString());
        content.put("status", vo.getOrderStatus());
        params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc());
        params.put("content", JSONObject.toJSONString(content));
        params.put("timestamp", System.currentTimeMillis() + "");
        String message = JSONObject.toJSONString(params);
        SendMessageDTO dto1 = new SendMessageDTO();
        dto1.setAppUserId(xpOrder.getAppUserId() + "");
        dto1.setMessage(message);
        R<String> stringR = xpPushMessageClient.sendStatus(dto1);
        //推送失败,重试3次
        if (stringR.getCode() != Constants.SUCCESS) {
            ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
            executor.execute(() -> {
                for (int i = 0; i < 3; i++) {
                    R<String> stringR1 = xpPushMessageClient.sendStatus(dto1);
                    if (stringR1.getCode() == Constants.SUCCESS) {
                        break;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    log.info("推送订单状态消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(dto1), xpOrder.getOrderNumber());
                }
            });
        }
        return R.ok();
    }
}