puzhibing
2026-04-15 a6715642ca882a2ee6ccc180cc517926dde38f8c
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/service/impl/XpPricingServiceImpl.java
@@ -14,12 +14,14 @@
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.enums.RouteStrategyKind;
import com.xiaopeng.api.dto.pushMessage.SendMessageDTO;
import com.xiaopeng.api.feignClient.account.UserRoutePlanRuleClient;
import com.xiaopeng.api.feignClient.account.XpAppUserClient;
import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
import com.xiaopeng.api.feignClient.map.XpMapClient;
import com.xiaopeng.api.feignClient.operation.XpPointClient;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.model.account.XpUserRoutePlanRule;
import com.xiaopeng.api.model.operation.*;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.vo.account.UserCouponVo;
@@ -134,6 +136,9 @@
    @Resource
    private XpPointClient xpPointClient;
    @Resource
    private UserRoutePlanRuleClient userRoutePlanRuleClient;
    @Value("${navigation.route.stale-seconds:60}")
    private int navigationStaleSeconds;
@@ -203,17 +208,6 @@
    @Override
    public RouteAndFareVo getRouteAndFare(RouteAndFareDto routeAndFareDto, String userId) {
//        // 判断是否5分钟内进行了查询 相同站点的起始点  并且是同时段
//        String key = "xp-map-query-" + routeAndFareDto.getOpenCityId()
//                + "-" + routeAndFareDto.getOrigin().getLongitude() + "-" + routeAndFareDto.getOrigin().getLatitude()
//                + "-" + routeAndFareDto.getDestination().getLongitude() + "-" + routeAndFareDto.getDestination().getLatitude() + "-" + getCurrentTimeSlot() + "-" + userId+routeAndFareDto.getUserCouponId();
//
//        if (redisService.hasKey(key)) {
//            String jsonStr = Objects.requireNonNull(redisService.getCacheObject(key)).toString();
//            RouteAndFareVo RouteAndFareVo = JSONObject.parseObject(jsonStr, RouteAndFareVo.class);
//            return (RouteAndFareVo);
//        }
        // 1. 基础数据查询
        Map<String, String> geocode = gdMapGeocodingUtil.geocode(routeAndFareDto.getOrigin().getLongitude().toString(), routeAndFareDto.getOrigin().getLatitude().toString());
        if(null == geocode){
@@ -227,9 +221,6 @@
        XpOpenCity xpOpenCity = openCities;
        routeAndFareDto.setOpenCityId(xpOpenCity.getId());
        XpRoutePlan xpRoutePlan = xpRoutePlanMapper.selectOne(new LambdaQueryWrapper<XpRoutePlan>().eq(XpRoutePlan::getAuditStatus, 2).eq(XpRoutePlan::getCityCode, cityCode));
        if (xpRoutePlan != null) {
            routeAndFareDto.setRoutePlanRule(xpRoutePlan.getRoutePlanRule());
        }
        Object userPref = redisService.getCacheObject(CacheConstants.USER_ROUTE_PREFERENCE + userId);
        if (userPref != null) {
            try {
@@ -244,77 +235,86 @@
            throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
        }
        List<RouteAndFareVo> list = new ArrayList<>();
        String[] split = xpRoutePlan.getRoutePlanRule().split(",");
        // 算距离
        R<RouteVo> distanceAndDuration = xpMapClient.getDistanceAndDuration(routeAndFareDto);
        if (distanceAndDuration.getCode() != 200) {
            throw new ServiceException("获取导肮信息失败", I18nKeyConstant.PATH_NOT_FOUND);
        }
        CountDownLatch countDownLatch = new CountDownLatch(split.length);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(split.length, split.length, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1000));
        for (int i = 0; i < split.length; i++) {
            String plan = split[i];
            routeAndFareDto.setRoutePlanRule(Integer.valueOf(plan));
            threadPoolExecutor.execute(()->{
                try {
                    // 算距离
                    R<RouteVo> distanceAndDuration = xpMapClient.getDistanceAndDuration(routeAndFareDto);
                    if (distanceAndDuration.getCode() != 200) {
                        throw new ServiceException("获取导肮信息失败", I18nKeyConstant.PATH_NOT_FOUND);
                    }
        RouteVo routeVo = distanceAndDuration.getData();
                    RouteVo routeVo = distanceAndDuration.getData();
        // 2. 计算价格(需要在并行任务前完成,因为优惠券查询需要价格)
        XpPricingCardVo xpPricingCardVo;
        if (xpPricing.getPricingType() == 1) {
            xpPricingCardVo = xpPricingUtil.calculationPrice(userId,
                    JSON.parseObject(xpPricing.getBasicPricingJson()),
                    JSON.parseArray(xpPricing.getStartingFareJson()),
                    routeVo.getDistance(), routeVo.getDuration(), 0, 0.0, xpPricing.getIsDynamicPrice(), routeAndFareDto.getOpenCityId(), xpPricing.getDynamicPricingJson()
            );
        } else {
            xpPricingCardVo = xpPricingUtil.calculationFixedPrice(userId,
                    JSON.parseObject(xpPricing.getBasicPricingJson()),
                    JSON.parseArray(xpPricing.getStartingFareJson()),
                    routeVo.getDistance(), routeVo.getDuration(), 0, 0.0, xpPricing.getIsDynamicPrice(), routeAndFareDto.getOpenCityId(), xpPricing.getDynamicPricingJson()
            );
        }
                    // 2. 计算价格(需要在并行任务前完成,因为优惠券查询需要价格)
                    XpPricingCardVo xpPricingCardVo;
                    if (xpPricing.getPricingType() == 1) {
                        xpPricingCardVo = xpPricingUtil.calculationPrice(userId,
                                JSON.parseObject(xpPricing.getBasicPricingJson()),
                                JSON.parseArray(xpPricing.getStartingFareJson()),
                                routeVo.getDistance(), routeVo.getDuration(), 0, 0.0, xpPricing.getIsDynamicPrice(), routeAndFareDto.getOpenCityId(), xpPricing.getDynamicPricingJson()
                        );
                    } else {
                        xpPricingCardVo = xpPricingUtil.calculationFixedPrice(userId,
                                JSON.parseObject(xpPricing.getBasicPricingJson()),
                                JSON.parseArray(xpPricing.getStartingFareJson()),
                                routeVo.getDistance(), routeVo.getDuration(), 0, 0.0, xpPricing.getIsDynamicPrice(), routeAndFareDto.getOpenCityId(), xpPricing.getDynamicPricingJson()
                        );
                    }
        // 优惠券:null=自动最佳;0=不使用;>0=指定券
        XpPricingCardVo finalXpPricingCardVo = xpPricingCardVo;
        R<UserCouponVo> coupon = null;
        CompletableFuture<R<UserCouponVo>> couponFuture=null;
        Long ucId = routeAndFareDto.getUserCouponId();
        if (Long.valueOf(0L).equals(ucId)) {
            coupon = R.ok(new UserCouponVo());
        } else if (ucId != null && ucId > 0L) {
            coupon = xpAppUserCouponClient.getUserCoupon(new GetUserCouponDto(Long.valueOf(userId), finalXpPricingCardVo.getTotalPrice(), routeAndFareDto.getOpenCityId(), ucId));
            if(coupon.getCode()==200 && coupon.getData().getStatus()==2){
                throw new ServiceException("优惠券不满足条件", I18nKeyConstant.COUPON_NOT_SATISFY);
            }
        } else {
            couponFuture= CompletableFuture.supplyAsync(
                    () -> xpAppUserCouponClient.getUserCoupon(
                            new GetUserCouponDto(Long.valueOf(userId), finalXpPricingCardVo.getTotalPrice(), routeAndFareDto.getOpenCityId(),null)
                        ),
                    executorService
            );
        }
                    // 优惠券:null=自动最佳;0=不使用;>0=指定券
                    XpPricingCardVo finalXpPricingCardVo = xpPricingCardVo;
                    R<UserCouponVo> coupon = null;
                    CompletableFuture<R<UserCouponVo>> couponFuture=null;
                    Long ucId = routeAndFareDto.getUserCouponId();
                    if (Long.valueOf(0L).equals(ucId)) {
                        coupon = R.ok(new UserCouponVo());
                    } else if (ucId != null && ucId > 0L) {
                        coupon = xpAppUserCouponClient.getUserCoupon(new GetUserCouponDto(Long.valueOf(userId), finalXpPricingCardVo.getTotalPrice(), routeAndFareDto.getOpenCityId(), ucId));
                        if(coupon.getCode()==200 && coupon.getData().getStatus()==2){
                            throw new ServiceException("优惠券不满足条件", I18nKeyConstant.COUPON_NOT_SATISFY);
                        }
                    } else {
                        couponFuture= CompletableFuture.supplyAsync(
                                () -> xpAppUserCouponClient.getUserCoupon(
                                        new GetUserCouponDto(Long.valueOf(userId), finalXpPricingCardVo.getTotalPrice(), routeAndFareDto.getOpenCityId(),null)
                                ),
                                executorService
                        );
                    }
        // 3. 并行执行远程服务调用 判断是否同一经营区域
        CompletableFuture<R<Boolean>> diagnosisAreaFuture = CompletableFuture.supplyAsync(
                () -> xpMapClient.diagnosisArea(routeAndFareDto),
                executorService
        );
                    // 3. 并行执行远程服务调用 判断是否同一经营区域
                    CompletableFuture<R<Boolean>> diagnosisAreaFuture = CompletableFuture.supplyAsync(
                            () -> xpMapClient.diagnosisArea(routeAndFareDto),
                            executorService
                    );
        // 4. 等待所有并行任务完成并获取结果
        R<Boolean> diagnosisResult = diagnosisAreaFuture.join();
        R<UserCouponVo> couponResult =null;
        if (Long.valueOf(0L).equals(ucId) || (ucId != null && ucId > 0L)) {
            couponResult = coupon;
        } else {
            couponResult = couponFuture.join();
        }
                    // 4. 等待所有并行任务完成并获取结果
                    R<Boolean> diagnosisResult = diagnosisAreaFuture.join();
                    R<UserCouponVo> couponResult =null;
                    if (Long.valueOf(0L).equals(ucId) || (ucId != null && ucId > 0L)) {
                        couponResult = coupon;
                    } else {
                        couponResult = couponFuture.join();
                    }
        // 5. 处理诊断结果
        if (diagnosisResult.getCode() != R.SUCCESS) {
            throw new RuntimeException(diagnosisResult.getMsg());
        }
        if (!diagnosisResult.getData()) {
            throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
        }
                    // 5. 处理诊断结果
                    if (diagnosisResult.getCode() != R.SUCCESS) {
                        throw new RuntimeException(diagnosisResult.getMsg());
                    }
                    if (!diagnosisResult.getData()) {
                        throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION);
                    }
//        // 6. 处理路线结果
//        if (routeResult.getCode() != 200) {
@@ -322,102 +322,124 @@
//        }
//        RouteVo routeVo = routeResult.getData();
        // 起终点最小距离 走缓存
        Integer minOrderDistance;
        Object minOrderDistanceObj = redisService.getCacheObject(CacheConstants.MIN_ORDER_DISTANCE);
        if (minOrderDistanceObj != null) {
            minOrderDistance = Integer.valueOf(minOrderDistanceObj.toString());
        } else {
            minOrderDistance = systemSettingMapper.selectOne(null).getMinOrderDistance();
        }
        if (routeVo.getDistance() < Integer.valueOf(minOrderDistance)) {
            throw new ServiceException("当前上下车点距离过近,建议步行前往", I18nKeyConstant.TO_WORK);
        }
                    // 起终点最小距离 走缓存
                    Integer minOrderDistance;
                    Object minOrderDistanceObj = redisService.getCacheObject(CacheConstants.MIN_ORDER_DISTANCE);
                    if (minOrderDistanceObj != null) {
                        minOrderDistance = Integer.valueOf(minOrderDistanceObj.toString());
                    } else {
                        minOrderDistance = systemSettingMapper.selectOne(null).getMinOrderDistance();
                    }
                    if (routeVo.getDistance() < Integer.valueOf(minOrderDistance)) {
                        throw new ServiceException("当前上下车点距离过近,建议步行前往", I18nKeyConstant.TO_WORK);
                    }
        // 7. 处理优惠券结果
        if (couponResult.getCode() != R.SUCCESS) {
            throw new RuntimeException(couponResult.getMsg());
        }
        UserCouponVo userCouponVo = couponResult.getData();
        if (userCouponVo != null) {
            Double money = userCouponVo.getMoney();
            money = new BigDecimal(money).setScale(2, RoundingMode.HALF_UP).doubleValue();
            xpPricingCardVo.setCoupon(String.valueOf(money));
            if (xpPricingCardVo.getTotalPrice() > money) {
                xpPricingCardVo.setSystemDiscount(xpPricingCardVo.getTotalPrice() - money);
            }
                    // 7. 处理优惠券结果
                    if (couponResult.getCode() != R.SUCCESS) {
                        throw new RuntimeException(couponResult.getMsg());
                    }
                    UserCouponVo userCouponVo = couponResult.getData();
                    if (userCouponVo != null) {
                        Double money = userCouponVo.getMoney();
                        money = new BigDecimal(money).setScale(2, RoundingMode.HALF_UP).doubleValue();
                        xpPricingCardVo.setCoupon(String.valueOf(money));
                        if (xpPricingCardVo.getTotalPrice() > money) {
                            xpPricingCardVo.setSystemDiscount(xpPricingCardVo.getTotalPrice() - money);
                        }
        }
                    }
        // 8. 构建响应对象
        RouteAndFareVo routeAndFareVo = new RouteAndFareVo();
        routeAndFareVo.setRoute(routeVo);
        // 转2位小数处理
        xpPricingCardVo.setTotalPriceStr(new BigDecimal(xpPricingCardVo.getTotalPrice()).setScale(2, RoundingMode.HALF_UP).toString());
        xpPricingCardVo.setStartPriceStr(new BigDecimal(xpPricingCardVo.getStartPrice()).setScale(2, RoundingMode.HALF_UP).toString());
        xpPricingCardVo.setDistancePriceStr(new BigDecimal(xpPricingCardVo.getDistancePrice()).setScale(2, RoundingMode.HALF_UP).toString());
        xpPricingCardVo.setDurationPriceStr(new BigDecimal(xpPricingCardVo.getDurationPrice()).setScale(2, RoundingMode.HALF_UP).toString());
        xpPricingCardVo.setSystemDiscountStr(new BigDecimal(xpPricingCardVo.getSystemDiscount()).setScale(2, RoundingMode.HALF_UP).toString());
                    // 8. 构建响应对象
                    RouteAndFareVo routeAndFareVo = new RouteAndFareVo();
                    routeAndFareVo.setRoutePlan(plan);
                    routeAndFareVo.setRoute(routeVo);
                    // 转2位小数处理
                    xpPricingCardVo.setTotalPriceStr(new BigDecimal(xpPricingCardVo.getTotalPrice()).setScale(2, RoundingMode.HALF_UP).toString());
                    xpPricingCardVo.setStartPriceStr(new BigDecimal(xpPricingCardVo.getStartPrice()).setScale(2, RoundingMode.HALF_UP).toString());
                    xpPricingCardVo.setDistancePriceStr(new BigDecimal(xpPricingCardVo.getDistancePrice()).setScale(2, RoundingMode.HALF_UP).toString());
                    xpPricingCardVo.setDurationPriceStr(new BigDecimal(xpPricingCardVo.getDurationPrice()).setScale(2, RoundingMode.HALF_UP).toString());
                    xpPricingCardVo.setSystemDiscountStr(new BigDecimal(xpPricingCardVo.getSystemDiscount()).setScale(2, RoundingMode.HALF_UP).toString());
        routeAndFareVo.setXpPricingCard(xpPricingCardVo);
                    routeAndFareVo.setXpPricingCard(xpPricingCardVo);
        FareVo fareVo = new FareVo();
        fareVo.setEstimatedDistanceKm(routeVo.getDistance().doubleValue() / 1000);
        fareVo.setEstimatedDurationMin(routeVo.getDuration() / 60);
                    FareVo fareVo = new FareVo();
                    fareVo.setEstimatedDistanceKm(routeVo.getDistance().doubleValue() / 1000);
                    fareVo.setEstimatedDurationMin(routeVo.getDuration() / 60);
        // 9. 设置费用信息
        fareVo.setOriginalFare(xpPricingCardVo.getTotalPrice());
        fareVo.setOriginalFareStr(new BigDecimal(fareVo.getOriginalFare()).setScale(2, RoundingMode.HALF_UP).toString());
        if (userCouponVo != null) {
            if(userCouponVo.getMoney()>fareVo.getOriginalFare()){
                fareVo.setDiscountAmount(fareVo.getOriginalFare());
                fareVo.setFinalFare(0.00);
            }else {
                fareVo.setDiscountAmount(userCouponVo.getMoney());
                fareVo.setFinalFare(fareVo.getOriginalFare() - fareVo.getDiscountAmount());
            }
            if(fareVo.getFinalFare()>0){
                fareVo.setSystemDiscount(fareVo.getFinalFare());
                fareVo.setFinalFare(0.00);
            }
            fareVo.setCouponId(userCouponVo.getId());
        } else {
            fareVo.setDiscountAmount(0.00);
            fareVo.setFinalFare(fareVo.getOriginalFare());
            fareVo.setSystemDiscount(fareVo.getFinalFare());
            fareVo.setFinalFare(0.00);
        }
                    // 9. 设置费用信息
                    fareVo.setOriginalFare(xpPricingCardVo.getTotalPrice());
                    fareVo.setOriginalFareStr(new BigDecimal(fareVo.getOriginalFare()).setScale(2, RoundingMode.HALF_UP).toString());
                    if (userCouponVo != null) {
                        if(userCouponVo.getMoney()>fareVo.getOriginalFare()){
                            fareVo.setDiscountAmount(fareVo.getOriginalFare());
                            fareVo.setFinalFare(0.00);
                        }else {
                            fareVo.setDiscountAmount(userCouponVo.getMoney());
                            fareVo.setFinalFare(fareVo.getOriginalFare() - fareVo.getDiscountAmount());
                        }
                        if(fareVo.getFinalFare()>0){
                            fareVo.setSystemDiscount(fareVo.getFinalFare());
                            fareVo.setFinalFare(0.00);
                        }
                        fareVo.setCouponId(userCouponVo.getId());
                    } else {
                        fareVo.setDiscountAmount(0.00);
                        fareVo.setFinalFare(fareVo.getOriginalFare());
                        fareVo.setSystemDiscount(fareVo.getFinalFare());
                        fareVo.setFinalFare(0.00);
                    }
        // 10. 检查等待时间
        Integer waitTime = getWaitTime(routeAndFareDto.getOrigin().getLongitude(), routeAndFareDto.getOrigin().getLatitude());
                    // 10. 检查等待时间
                    Integer waitTime = getWaitTime(routeAndFareDto.getOrigin().getLongitude(), routeAndFareDto.getOrigin().getLatitude());
//        if (waitTime > 3) {
//            throw new ServiceException("当前区域正在等待中,请耐心等待", I18nKeyConstant.WAITING_TIME);
//        }
        fareVo.setWaitingTime(waitTime);
                    fareVo.setWaitingTime(waitTime);
        // 11. 生成订单ID并缓存
        String id = CacheConstants.ORD + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
        redisService.setCacheObject(CacheConstants.ORD + id + userId, xpPricingCardVo, 1l, TimeUnit.DAYS);
        fareVo.setId(id);
                    // 11. 生成订单ID并缓存
                    String id = CacheConstants.ORD + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
                    redisService.setCacheObject(CacheConstants.ORD + id + userId, xpPricingCardVo, 1l, TimeUnit.DAYS);
                    fareVo.setId(id);
        // 12. 设置费用信息
        fareVo.setFinalFareStr(new BigDecimal(fareVo.getFinalFare()).setScale(2, RoundingMode.HALF_UP).toString());
        fareVo.setOriginalFare(new BigDecimal(fareVo.getOriginalFare()).setScale(2,RoundingMode.HALF_UP).doubleValue());
        fareVo.setSystemDiscount(new BigDecimal(fareVo.getSystemDiscount() == null ? 0 : fareVo.getSystemDiscount()).setScale(2,RoundingMode.HALF_UP).doubleValue());
        routeAndFareVo.setFareEstimate(fareVo);
                    // 12. 设置费用信息
                    fareVo.setFinalFareStr(new BigDecimal(fareVo.getFinalFare()).setScale(2, RoundingMode.HALF_UP).toString());
                    fareVo.setOriginalFare(new BigDecimal(fareVo.getOriginalFare()).setScale(2,RoundingMode.HALF_UP).doubleValue());
                    fareVo.setSystemDiscount(new BigDecimal(fareVo.getSystemDiscount() == null ? 0 : fareVo.getSystemDiscount()).setScale(2,RoundingMode.HALF_UP).doubleValue());
                    routeAndFareVo.setFareEstimate(fareVo);
        routeAndFareVo.getXpPricingCard().setFinalFareStr(fareVo.getFinalFareStr());
                    routeAndFareVo.getXpPricingCard().setFinalFareStr(fareVo.getFinalFareStr());
                    list.add(routeAndFareVo);
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    countDownLatch.countDown();
                }
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(list.isEmpty()){
            throw new RuntimeException("获取导航信息失败");
        }
//        String voJsonStr = JSONObject.toJSONString(routeAndFareVo);
//         进行缓存
//        redisService.setCacheObject(key, voJsonStr, 5l, TimeUnit.MINUTES);
        //缓存导航数据,用于下单后推送导航给车端和乘客端
        redisService.setCacheObject("ORDER_NAVIGATION_END_DATA:" + userId, JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
        return routeAndFareVo;
        redisService.setCacheObject("ORDER_NAVIGATION_END_LIST_DATA:" + userId, JSON.toJSONString(list), 24L, TimeUnit.HOURS);
        //查询乘客偏好设置
        XpUserRoutePlanRule xpUserRoutePlanRule = userRoutePlanRuleClient.getXpUserRoutePlanRule(userId).getData();
        if(null != xpUserRoutePlanRule){
            String routePlanRule = xpUserRoutePlanRule.getRoutePlanRule();
            RouteAndFareVo routeAndFareVo = list.stream().filter(s -> s.getRoutePlan().equals(routePlanRule)).findFirst().orElse(null);
            return routeAndFareVo;
        }
        return list.get(0);
    }
@@ -1118,7 +1140,7 @@
            configuredKinds.addAll(RouteStrategyKind.defaultPreferenceKinds());
        } else {
            for (XpRoutePlan xpRoutePlan : xpRoutePlans) {
                Integer strategy = xpRoutePlan.getRoutePlanRule();
                String strategy = xpRoutePlan.getRoutePlanRule();
                if (strategy == null) {
                    continue;
                }