package com.xiaopeng.itinerary.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.xiaopeng.api.dto.automaticPilot.PushOrderDto; import com.xiaopeng.api.dto.operation.ReassignOrderDTO; import com.xiaopeng.api.dto.order.OrderChangeDto; import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient; import com.xiaopeng.api.feignClient.map.XpMapClient; import com.xiaopeng.api.feignClient.operation.ReassignOrderClient; import com.xiaopeng.api.feignClient.operation.XpPointClient; import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient; import com.xiaopeng.api.feignClient.order.XpOrderClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.operation.XpElectronicFence; import com.xiaopeng.api.model.operation.XpElectronicFenceArea; import com.xiaopeng.api.model.operation.XpPoint; import com.xiaopeng.api.model.operation.XpSystemSetting; import com.xiaopeng.api.model.order.OrderTrajectory; import com.xiaopeng.api.model.order.XpOrder; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.api.vo.automaticPilot.protobuf.OrderOperationType; import com.xiaopeng.api.vo.operation.RouteOptionVo; import com.xiaopeng.api.vo.operation.RouteVo; import com.xiaopeng.common.core.constant.CacheConstants; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.enums.CancelOrderSceneEnum; import com.xiaopeng.common.core.enums.OrderStatusEnum; import com.xiaopeng.common.core.exception.ServiceException; import com.xiaopeng.common.core.utils.SensitiveDataCryptoUtil; import com.xiaopeng.common.core.utils.StringUtils; import com.xiaopeng.common.redis.service.RedisService; import com.xiaopeng.itinerary.constant.I18nKeyConstant; import com.xiaopeng.itinerary.mapper.XpElectronicFenceAreaMapper; import com.xiaopeng.itinerary.mapper.XpElectronicFenceMapper; import com.xiaopeng.itinerary.mapper.XpOpenCityMapper; import com.xiaopeng.itinerary.mapper.XpRoutePlanMapper; import com.xiaopeng.itinerary.navigation.MultiRouteSnapshotPayload; import com.xiaopeng.itinerary.service.ActiveOrderService; import com.xiaopeng.itinerary.service.XpPointService; import com.xiaopeng.itinerary.service.XpPricingService; import com.xiaopeng.itinerary.utils.OfficialPartnerUtil; import com.xiaopeng.itinerary.utils.map.GDMapGeocodingUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.List; import java.util.StringJoiner; import java.util.concurrent.TimeUnit; @Slf4j @Service public class ActiveOrderServiceImpl implements ActiveOrderService { @Resource private GDMapGeocodingUtil gdMapGeocodingUtil; @Resource private XpOpenCityMapper xpOpenCityMapper; @Resource private XpOrderClient xpOrderClient; @Resource private XpSystemSettingClient xpSystemSettingClient; @Resource private XpPricingService xpPricingService; @Resource private XpMapClient xpMapClient; @Resource private XpElectronicFenceAreaMapper xpElectronicFenceAreaMapper; @Autowired private XpElectronicFenceMapper xpElectronicFenceMapper; @Autowired private XpPointService xpPointService; @Resource private XpPointClient xpPointClient; @Resource private RedisService redisService; @Resource private XpRoutePlanMapper xpRoutePlanMapper; @Resource private XpVehicleClient vehicleClient; @Resource private OrderMissionClient orderMissionClient; @Resource private OfficialPartnerUtil officialPartnerUtil; @Resource private MongoTemplate mongoTemplate; /* public void getRouteAndFareParamValidate(RouteAndFareDto routeAndFareDto, String userId) { //获取订单信息 R xpOrderR = xpOrderClient.queryOrderById(routeAndFareDto.getOrderId()); if (xpOrderR.getCode() != R.SUCCESS || xpOrderR.getData() == null) { throw new ServiceException("订单不存在"); } // 1. 基础数据查询 Map geocode = gdMapGeocodingUtil.geocode(routeAndFareDto.getOrigin().getLongitude().toString(), routeAndFareDto.getOrigin().getLatitude().toString()); if(null == geocode){ throw new ServiceException("获取城市信息失败", I18nKeyConstant.CITY_NOT_FOUND); } Long cityCode = routeAndFareDto.getOpenCityId(); XpOpenCity openCities = xpOpenCityMapper.selectById(cityCode); if (openCities == null ) { throw new ServiceException("获取城市信息失败", I18nKeyConstant.CITY_NOT_FOUND); } XpPricing xpPricing = xpPricingService.getOne(new LambdaQueryWrapper().eq(XpPricing::getCityId, routeAndFareDto.getOpenCityId())); if (xpPricing == null) { throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION); } routeAndFareDto.setRoutePlanRule(xpOrderR.getData().getRoutePlanRule()); // 算距离 R distanceAndDuration = xpMapClient.getDistanceAndDuration(routeAndFareDto); if (distanceAndDuration.getCode() != 200) { throw new ServiceException("获取导肮信息失败", I18nKeyConstant.PATH_NOT_FOUND); } RouteVo routeVo = distanceAndDuration.getData(); } */ @Override public void orderChange(OrderChangeDto dto, String uid){ //获取订单信息 R xpOrderR = xpOrderClient.queryOrderById(dto.getOrderId()); if (xpOrderR.getCode() != R.SUCCESS || xpOrderR.getData() == null) { throw new ServiceException("订单不存在"); } //获取系统配置 XpSystemSetting systemSetting = xpSystemSettingClient.getSystemSettingOne().getData(); if(systemSetting == null){ throw new ServiceException("获取行程配置错误"); } Integer orderChange = systemSetting.getXczCaCount();// 从配置文件读取 修改订单目的地次数 XpOrder order = xpOrderR.getData(); //判断订单修改的次数 //需要加上豁免的情况 if(order.getOrderChange() >= orderChange){ if(order.getStatus() == 6){ //计算平均时速小于设定值,可豁免限制 Integer xczHmSpeedPerHour = systemSetting.getXczHmSpeedPerHour(); Integer xczHmDuration = systemSetting.getXczHmDuration(); LocalDateTime localDateTime = LocalDateTime.now().minusMinutes(xczHmDuration); List orderTrajectories = mongoTemplate.find(Query.query(Criteria.where("orderId").is(order.getId()).and("createTime").gt(localDateTime)), OrderTrajectory.class); if(orderTrajectories.isEmpty()){ throw new ServiceException("目的地修改次数已超上限"); } double speed = orderTrajectories.stream().map(OrderTrajectory::getSpeed).reduce(Double::sum).orElse(0D) / orderTrajectories.size(); if(speed > xczHmSpeedPerHour){ throw new ServiceException("目的地修改次数已超上限"); } }else{ throw new ServiceException("目的地修改次数已超上限"); } } if(order.getVehicleId() == null){ throw new ServiceException("行驶中的车辆信息错误"); } XpVehicle xpVehicle = vehicleClient.queryById(order.getVehicleId()).getData(); if(xpVehicle== null){ throw new ServiceException("获取行驶中的车辆信息错误"); } //剩余里程xx米,或者 剩余时间xx分钟 禁止修改目的地 //获取订单的 状态 0=已取消,1=待接单,2=待出发,3=接驾中,4=待客上车,5=乘客已上车,6=服务中,7=待客下车,8=待付款,9=待评价,10=已完成 if(order.getStatus() == 6){ Object cacheObject = redisService.getCacheObject(CacheConstants.navigationEnd(uid)); if(cacheObject != null){ RouteVo routeRemain = JSON.parseObject(cacheObject.toString(), RouteVo.class); Integer xczSyDistance = routeRemain.getDistance();//行程中剩余里程 Integer xczSyTime = routeRemain.getDuration();//行程中剩余时间 if(systemSetting.getXczSyDistance() > xczSyDistance || systemSetting.getXczSyTime() * 60 > xczSyTime){ throw new ServiceException("即将达到终点,禁止修改目的地"); } } } // 是否在运营区域时间内 XpElectronicFenceArea xpElectronicFenceArea = xpElectronicFenceAreaMapper.selectById(order.getXpElectronicFenceAreaId()); XpElectronicFence xpElectronicFence = xpElectronicFenceMapper.selectById(xpElectronicFenceArea.getElectronicId()); String operationStrategy = xpElectronicFence.getOperationStrategy(); Boolean inOperationTime = xpPricingService.isInOperationTime(operationStrategy); if (!inOperationTime && xpElectronicFence.getFailureType()!=1) { log.info("当前区域暂未开通,修改失败 {}", uid); throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION); } boolean inTime = xpPointClient.nowInTimePoint(dto.getEndPointId()).getData(); if (!inTime) { throw new ServiceException("终点点位未开通服务", I18nKeyConstant.NO_CURRENT_REGION); } // 终点 XpPoint endXpPoint = xpPointService.getById(dto.getEndPointId()); if(endXpPoint ==null || endXpPoint.getOperationStatus()!=2){ throw new ServiceException("该站点已停止运营", 200,I18nKeyConstant.NO_CURRENT_POINT); } //修改订单数据 XpOrder xpOrder = new XpOrder(); xpOrder.setId(order.getId()); xpOrder.setEndLon(endXpPoint.getPointLon()); xpOrder.setEndLat(endXpPoint.getPointLat()); xpOrder.setEndAddress(endXpPoint.getPointAddress()); xpOrder.setEndPointId(dto.getEndPointId()); xpOrder.setEndPointName(endXpPoint.getPointName()); Long couponRef = dto.getCouponId(); xpOrder.setCouponId(couponRef != null && couponRef > 0L ? couponRef : null); xpOrder.setUpdateTime(LocalDateTime.now()); xpOrder.setOrderChange(order.getOrderChange()+1); xpOrderClient.updateOrder(xpOrder); //获取距离和时间 this.getDD(uid,dto); //将修改信息存入到redis, // 获取起点经纬度 XpPoint xpPoint = xpPointService.getById(order.getStartPointId()); final Integer planRuleForQueue = dto.getSelectedRoutePlanRule(); StringJoiner points = new StringJoiner("_"); points.add(order.getId().toString()); points.add(xpPoint.getPointLon() + "," + xpPoint.getPointLat()); points.add("0"); points.add(uid); points.add(order.getOrderNumber()); points.add(dto.getDistance()+""); points.add(dto.getDuration()+""); // todo 临时关闭,不知道这里修改队列数据干嘛 // String key = CacheConstants.QUEUE_POINT_ID + "-" + xpPoint.getId() + "-" + xpPoint.getPointLon() + "," + xpPoint.getPointLat(); // if (planRuleForQueue == null) { // redisService.addToTail(key,points+"_"+null); // } else { // redisService.addToTail(key,points+"_"+planRuleForQueue); // } // log.info("订单推单:{} {}", key, redisService.getCacheList(key)); // xpOrder.setQueueName(key); // xpOrderClient.updateOrder(xpOrder); //给车端推送修改目的地报文 String vin = SensitiveDataCryptoUtil.decryptIfPossible(xpVehicle.getVehicleVin()); PushOrderDto pushOrderDto = new PushOrderDto(); pushOrderDto.setOrderId(order.getId().toString()); pushOrderDto.setStartTaskId(order.getXpuStartTaskId()); pushOrderDto.setEndTaskId(order.getXpuEndTaskId()); pushOrderDto.setVin(vin); pushOrderDto.setOperation_type(OrderOperationType.CLOUD_CHANGE_DESTINATION); pushOrderDto.setEndLongitude(endXpPoint.getPointLon()); pushOrderDto.setEndLatitude(endXpPoint.getPointLat()); pushOrderDto.setEndPoiName(endXpPoint.getPointName()); pushOrderDto.setCancelScene(CancelOrderSceneEnum.NORMAL_CANCEL.getCode()); orderMissionClient.updateEndAddress(pushOrderDto); log.info("订单下发XPU修改目的地成功 {}", order.getId()); // 判断当前订单的车辆是否有连环派单,然后判断是都还满足连环派单的条件,不满足则需要重新派单 String json = redisService.getCacheObject(CacheConstants.nextOrder(order.getId().toString())); if (StringUtils.isNotEmpty(json)){ JSONObject jsonObject = JSON.parseObject(json); Long nextOrderId = jsonObject.getLong("orderId"); XpOrder nextOrder = xpOrderClient.queryOrderById(nextOrderId).getData(); if(null != nextOrder && nextOrder.getStatus() == OrderStatusEnum.PICK_UP.getCode()){ redisService.setCacheObject(CacheConstants.nextOrder(order.getId().toString()),null); ReassignOrderDTO reassignOrderDTO = new ReassignOrderDTO(); reassignOrderDTO.setUid(xpOrder.getAppUserId().toString()); reassignOrderDTO.setOrderNo(xpOrder.getOrderNumber()); reassignOrderDTO.setCount(10); reassignOrderDTO.setLongitude(xpOrder.getStartLon()); reassignOrderDTO.setLatitude(xpOrder.getStartLon()); reassignOrderClient.reassignOrder(reassignOrderDTO); } } //流量接入-订单推送 推送合作商修改目的地消息 if(null != order.getOfficialPartnerId()){ officialPartnerUtil.pushUpdateEndAddress(order.getOfficialPartnerId(), xpOrder); } } @Resource private ReassignOrderClient reassignOrderClient; /** * 获取距离和时间 * @param uid * @param dto */ public void getDD (String uid, OrderChangeDto dto ){ Integer distance = 0; Integer duration = 0; if (dto.getNavigationSnapshotId() != null && dto.getSelectedRouteId() != null) { String snap = redisService.getCacheObject(CacheConstants.ORDER_MULTI_ROUTE_SNAPSHOT + uid + ":" + dto.getNavigationSnapshotId()); if (snap != null) { MultiRouteSnapshotPayload snapPayload = JSON.parseObject(snap, MultiRouteSnapshotPayload.class); RouteOptionVo opt = snapPayload.getRoutes().stream() .filter(r2 -> dto.getSelectedRouteId().equals(r2.getPathFingerprint())) .findFirst() .orElse(null); if (opt != null && opt.getRoute() != null) { distance = opt.getRoute().getDistance(); duration = opt.getRoute().getDuration(); redisService.setCacheObject("ORDER_NAVIGATION_END_DATA:" + uid, JSON.toJSONString(opt.getRoute()), 24L, TimeUnit.HOURS); if (dto.getSelectedRoutePlanRule() == null) { dto.setSelectedRoutePlanRule(opt.getPrimaryRoutePlanRule()); } } } } if (distance == 0 && duration == 0) { Object cacheObject = redisService.getCacheObject("ORDER_NAVIGATION_END_DATA:" + uid); if (cacheObject != null) { RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class); distance = routeVo.getDistance(); duration = routeVo.getDuration(); } } dto.setDistance(distance); dto.setDuration(duration); } }