Merge remote-tracking branch 'origin/master'
| | |
| | | public R<UserCouponVo> getUserCoupon(@RequestBody GetUserCouponDto dto) { |
| | | UserCouponVo userCouponVo = new UserCouponVo(); |
| | | // 获取用户所有优惠券 |
| | | List<XpAppUserCoupon> couponList = xpAppUserCouponService.list(new LambdaQueryWrapper<XpAppUserCoupon>().eq(XpAppUserCoupon::getStatus, 1).eq(XpAppUserCoupon::getAppUserId, dto.getUserId())); |
| | | List<XpAppUserCoupon> couponList = xpAppUserCouponService.list(new LambdaQueryWrapper<XpAppUserCoupon>().eq(XpAppUserCoupon::getStatus, 1).eq(XpAppUserCoupon::getAppUserId, dto.getUserId()).apply("FIND_IN_SET({0}, open_city_id)", dto.getOpenCityId()) ); |
| | | if(couponList.isEmpty()){ |
| | | return R.ok(userCouponVo); |
| | | } |
| | | // 计算使用时间规则 |
| | | couponList = xpAppUserCouponService.timeRule(couponList); |
| | | if(couponList.isEmpty()){ |
| | | return R.ok(userCouponVo); |
| | | } |
| | | |
| | | // 优先用满足条件且抵扣金额最大的 |
| | | List<XpAppUserCoupon> discountUserCoupons = couponList.stream().filter(e -> e.getCouponType() == 1).sorted(Comparator.comparing(XpAppUserCoupon::getMoney).reversed()).collect(Collectors.toList()); |
| | | if(!discountUserCoupons.isEmpty()){ |
| | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 获取优惠券列表 |
| | | */ |
| | |
| | | import com.xiaopeng.account.model.vo.XpAppUserCouponVo; |
| | | import com.xiaopeng.api.model.account.XpAppUserCoupon; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * <p> |
| | | * 用户优惠券 服务类 |
| | |
| | | */ |
| | | boolean receive(ReceiveCouponDto dto, String uid); |
| | | |
| | | /** |
| | | * 根据时间规则筛选出优惠券 |
| | | * @param couponList |
| | | * @return |
| | | */ |
| | | List<XpAppUserCoupon> timeRule(List<XpAppUserCoupon> couponList); |
| | | |
| | | |
| | | } |
| | |
| | | package com.xiaopeng.account.service.impl; |
| | | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | |
| | | import com.xiaopeng.account.model.vo.XpAppUserCouponTotalVo; |
| | | import com.xiaopeng.account.model.vo.XpAppUserCouponVo; |
| | | import com.xiaopeng.account.service.IXpAppUserCouponService; |
| | | import com.xiaopeng.account.util.holiday.HolidayUtil; |
| | | import com.xiaopeng.api.model.account.XpAppUserCoupon; |
| | | import com.xiaopeng.common.core.utils.DateUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | /** |
| | |
| | | */ |
| | | @Service |
| | | public class XpAppUserCouponServiceImpl extends ServiceImpl<XpAppUserCouponMapper, XpAppUserCoupon> implements IXpAppUserCouponService { |
| | | |
| | | @Autowired |
| | | private HolidayUtil holidayUtil; |
| | | |
| | | /** |
| | | * 获取用户优惠券列表 |
| | |
| | | return vo; |
| | | } |
| | | |
| | | /** |
| | | * 领取优惠券 |
| | | * @param dto |
| | | * @param uid |
| | | * @return |
| | | */ |
| | | @Override |
| | | public boolean receive(ReceiveCouponDto dto, String uid) { |
| | | XpAppUserCoupon coupon = baseMapper.selectById(dto.getCouponId()); |
| | |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 时间规则 |
| | | * @param couponList |
| | | * @return |
| | | */ |
| | | @Override |
| | | public List<XpAppUserCoupon> timeRule(List<XpAppUserCoupon> couponList) { |
| | | List<XpAppUserCoupon> xpAppUserCoupons = new ArrayList<>(); |
| | | |
| | | for (XpAppUserCoupon coupon : couponList) { |
| | | String timeJson = coupon.getTimeJson(); |
| | | Boolean inOperationTime = isInOperationTime(timeJson); |
| | | if(inOperationTime){ |
| | | xpAppUserCoupons.add(coupon); |
| | | } |
| | | } |
| | | |
| | | return xpAppUserCoupons; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 是否在运营内 |
| | | * @param timeJson 规则json字符串 |
| | | * @return |
| | | */ |
| | | private Boolean isInOperationTime(String timeJson) { |
| | | JSONArray jsonArray = JSONArray.parseArray(timeJson); |
| | | Integer holidayToday = holidayUtil.isHolidayToday(); |
| | | for (Object o : jsonArray) { |
| | | JSONObject jsonObject =JSONObject.parseObject(o.toString()); |
| | | String type = jsonObject.getString("type"); |
| | | if(type.equals(holidayToday.toString())){ |
| | | JSONArray time = jsonObject.getJSONArray("time"); |
| | | // 判断当前时间 是否在time时间段中 |
| | | for (Object object : time) { |
| | | String[] timeArray = object.toString().split("-"); |
| | | String startTime = timeArray[0]; |
| | | String endTime = timeArray[1]; |
| | | boolean currentTimeInRange = DateUtils.isCurrentTimeInRange(startTime, endTime); |
| | | if(currentTimeInRange){ |
| | | return true; |
| | | } |
| | | } |
| | | }else if(type.equals("3")){ |
| | | // 判断是什么类型 0每天 1-7 想起 |
| | | String typeStr = jsonObject.getString("typeStr"); |
| | | // 查看今天周几 |
| | | Integer week = DateUtils.getWeek(); |
| | | // 包含每天 或者 包含当天 |
| | | if(typeStr.contains("0") || typeStr.contains(week.toString())){ |
| | | JSONArray time = jsonObject.getJSONArray("time"); |
| | | // 判断当前时间 是否在time时间段中 |
| | | for (Object object : time) { |
| | | String[] timeArray = object.toString().split("-"); |
| | | String startTime = timeArray[0]; |
| | | String endTime = timeArray[1]; |
| | | boolean currentTimeInRange = DateUtils.isCurrentTimeInRange(startTime, endTime); |
| | | if(currentTimeInRange){ |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.xiaopeng.account.util.holiday; |
| | | |
| | | import cn.hutool.http.HttpUtil; |
| | | import com.alibaba.fastjson2.JSONArray; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.xiaopeng.common.core.constant.CacheConstants; |
| | | import com.xiaopeng.common.core.utils.HttpUtils; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.time.LocalDate; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | |
| | | @Component |
| | | public class HolidayUtil { |
| | | |
| | | |
| | | @Autowired |
| | | private RedisService redisService; |
| | | |
| | | |
| | | public boolean isHoliday() { |
| | | LocalDate now = LocalDate.now(); |
| | | |
| | | // 判断缓存里面是否有节假日算法 |
| | | if (redisService.getCacheObject(CacheConstants.IS_HOLIDAY+now) != null && ("1").equals(redisService.getCacheObject(CacheConstants.IS_HOLIDAY+now).toString())) { |
| | | return true; |
| | | } |
| | | String result = HttpUtil.get("https://publicapi.xiaoai.me/holiday/day?date=" +now); |
| | | JSONObject jsonObject = JSONObject.parseObject(result); |
| | | Object data = jsonObject.get("data"); |
| | | JSONArray parse = JSONArray.parse(data.toString()); |
| | | for (int i = 0; i < parse.size(); i++) { |
| | | JSONObject jsonObject1 = parse.getJSONObject(i); |
| | | if (jsonObject1.get("daytype").toString().equals("1")) { |
| | | redisService.setCacheObject(CacheConstants.IS_HOLIDAY+now, "1", 1l, TimeUnit.DAYS); |
| | | return true; |
| | | } |
| | | } |
| | | redisService.setCacheObject(CacheConstants.IS_HOLIDAY+now, "0", 1l, TimeUnit.DAYS); |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 2非工作日 0工作日 1节假日 3调休日 |
| | | * @return |
| | | */ |
| | | public Integer isHolidayToday() { |
| | | LocalDate now = LocalDate.now(); |
| | | Object cacheObject = redisService.getCacheObject(CacheConstants.IS_DAY + now); |
| | | // 判断缓存里面是否有节假日算法 |
| | | if (cacheObject!=null) { |
| | | return Integer.valueOf(cacheObject.toString()); |
| | | } |
| | | String result = HttpUtils.sendGet("https://publicapi.xiaoai.me/holiday/day?date=" +now); |
| | | |
| | | // String result = HttpUtils.sendGet("https://publicapi.xiaoai.me/holiday/day?date=2026-01-04"); |
| | | JSONObject jsonObject = JSONObject.parseObject(result); |
| | | Object data = jsonObject.get("data"); |
| | | JSONArray parse = JSONArray.parse(data.toString()); |
| | | for (int i = 0; i < parse.size(); i++) { |
| | | JSONObject jsonObject1 = parse.getJSONObject(i); |
| | | String daytype = jsonObject1.get("daytype").toString(); |
| | | if (daytype.equals("0")) { |
| | | redisService.setCacheObject(CacheConstants.IS_DAY + now, "0", 1l, TimeUnit.DAYS); |
| | | return 0; |
| | | } else if (daytype.equals("1")) { |
| | | redisService.setCacheObject(CacheConstants.IS_DAY + now, "1", 1l, TimeUnit.DAYS); |
| | | return 1; |
| | | } else if (daytype.equals("2")) { |
| | | redisService.setCacheObject(CacheConstants.IS_DAY + now, "0", 1l, TimeUnit.DAYS); |
| | | return 0; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | @ApiModelProperty(value = "订单总金额") |
| | | private Double totalAmount; |
| | | |
| | | @ApiModelProperty(value = "开通城市id") |
| | | private Long openCityId; |
| | | } |
| | |
| | | @PostMapping("/inner/order/queryOrderByOrderNo") |
| | | R<XpOrder> queryOrderByOrderNo(@RequestParam String orderNo); |
| | | |
| | | R<Integer> getOrderNum(String timeStr); |
| | | |
| | | |
| | | } |
| | |
| | | @ApiModelProperty(value = "城市id集合") |
| | | private String openCityId; |
| | | |
| | | |
| | | @ApiModelProperty(value = "使用时间规则") |
| | | private String timeJson; |
| | | } |
| | |
| | | @TableField("price_rule") |
| | | private String priceRule; |
| | | |
| | | |
| | | @ApiModelProperty(value = "是否动态价格 0否 1是") |
| | | @TableField("is_dynamic_price") |
| | | private Integer isDynamicPrice; |
| | | |
| | | } |
| | |
| | | @Override |
| | | public WalkTimeVo getWalkTime(WalkTimeDto dto) { |
| | | WalkTimeVo walkTimeVo = new WalkTimeVo(); |
| | | String apiKey = "009f3714aca6a61e05d3e63ea03226c9"; |
| | | String apiKey = "66ae577f63898dae3016d599fda57221"; |
| | | // 创建服务实例 |
| | | GaodeMapService gaodeService = new GaodeMapService(apiKey); |
| | | AmapWalkingRouteUtil.WalkingRouteResult result = gaodeService.getWalkingRoute(dto.getStartLongitude()+","+dto.getStartLatitude(),dto.getEndLongitude()+","+dto.getEndLatitude()); |
| | |
| | | @Lazy |
| | | public class GDMapGeocodingUtil { |
| | | |
| | | private String key = "f11b217cdbb08cd780919ed7398c5504"; |
| | | private String key = "66ae577f63898dae3016d599fda57221"; |
| | | |
| | | @Autowired |
| | | private RestTemplate restTemplate; |
| | |
| | | routeAndFareDto.setRoutePlanRule(xpRoutePlan.getRoutePlanRule()); |
| | | } |
| | | |
| | | // XpPricing xpPricing = this.baseMapper.selectOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, routeAndFareDto.getOpenCityId())); |
| | | XpPricing xpPricing = this.baseMapper.selectOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, routeAndFareDto.getOpenCityId())); |
| | | // if (xpPricing == null) { |
| | | // throw new ServiceException("当前区域未开通服务", I18nKeyConstant.NO_CURRENT_REGION); |
| | | // } |
| | |
| | | () -> { |
| | | // 优惠券 |
| | | return xpAppUserCouponClient.getUserCoupon( |
| | | // new GetUserCouponDto(Long.valueOf(userId), xpPricingCardVo.getTotalPrice()) |
| | | new GetUserCouponDto(Long.valueOf(userId), 1d) |
| | | // new GetUserCouponDto(Long.valueOf(userId), xpPricingCardVo.getTotalPrice(),routeAndFareDto.getOpenCityId()) |
| | | new GetUserCouponDto(Long.valueOf(userId), 1d,routeAndFareDto.getOpenCityId()) |
| | | ); |
| | | }, |
| | | executorService |
| | |
| | | Integer onePushTime = xpTradingStrategy.getOnePushTime(); |
| | | int count = onePushTime / 3; |
| | | // 第一轮推单 |
| | | processOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | processPushOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | |
| | | // |
| | | // for (int i = 0; i < count; i++) { |
| | |
| | | // 第二轮推单 |
| | | Integer twoPushTime = xpTradingStrategy.getTwoPushTime(); |
| | | count = twoPushTime / 3; |
| | | processOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | processPushOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | |
| | | // 第三轮推单 |
| | | Integer threePushTime = xpTradingStrategy.getThreePushTime(); |
| | | count = threePushTime / 3; |
| | | processOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | processPushOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | |
| | | // 第四轮推单 |
| | | Integer fourPushTime = xpTradingStrategy.getFourPushTime(); |
| | | count = fourPushTime / 3; |
| | | processOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | processPushOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | |
| | | // 第五轮推单 |
| | | Integer fivePushTime = xpTradingStrategy.getFivePushTime(); |
| | | count = fivePushTime / 3; |
| | | processOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | processPushOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule); |
| | | |
| | | // 最终没找到车 |
| | | redisService.popFirstElement(quoteName); |
| | |
| | | * @param orderNo 订单号 |
| | | * @param xpTradingStrategy 规则 |
| | | */ |
| | | private void processOrder(String quoteName, int count, String uid, String[] split, String orderNo, XpTradingStrategy xpTradingStrategy, String distance, String duration, String planRule) { |
| | | private void processPushOrder(String quoteName, int count, String uid, String[] split, String orderNo, XpTradingStrategy xpTradingStrategy, String distance, String duration, String planRule) { |
| | | // 订单状态 |
| | | R<XpOrder> xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo); |
| | | if (xpOrderR.getCode() != 200) { |
| | |
| | | addTaxiPassengerVo.setAppId(""); |
| | | BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.addTaxiPassenger(addTaxiPassengerVo); |
| | | if (baseVehicleUserDto.getCode() == 200) { |
| | | |
| | | // TODO 下单 |
| | | // 绑定成功 弹出这个队列第一个订单 |
| | | redisService.popFirstElement(quoteName); |
| | | return; |
| | |
| | | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.xiaopeng.api.feignClient.order.XpOrderClient; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.common.redis.service.RedisService; |
| | | import com.xiaopeng.operation.utils.holiday.HolidayUtil; |
| | | import com.xiaopeng.operation.vo.XpPricingCardVo; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.util.*; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | /** |
| | | * 计算价格的工具类 |
| | |
| | | @Autowired |
| | | private HolidayUtil holidayUtil; |
| | | |
| | | @Autowired |
| | | private RedisService redisService; |
| | | |
| | | @Autowired |
| | | private XpOrderClient xpOrderClient; |
| | | |
| | | |
| | | /** |
| | | * 计算基础价格 |
| | | * @param rule |
| | | * @param distance |
| | | * @param duration |
| | | * @param wait |
| | | * @param waitMoney |
| | | * @param rule 基础规则 |
| | | * @param distance 里程 |
| | | * @param duration 时间 |
| | | * @param wait 时间 |
| | | * @param waitMoney 等待费 |
| | | * @param openCityId 开通城市id |
| | | * @param isDynamicPriceStatus 是否开启动态调价 |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public XpPricingCardVo calculationPrice(JSONObject rule, JSONArray startingFareJson, double distance, long duration, long wait, Double waitMoney) { |
| | | public XpPricingCardVo calculationPrice(String uid,JSONObject rule, JSONArray startingFareJson, double distance, long duration, long wait, Double waitMoney,Integer isDynamicPriceStatus,Long openCityId,String dynamicPricingJson) { |
| | | |
| | | |
| | | // 默认费率1 |
| | | double priceRate=1; |
| | | if(isDynamicPriceStatus==1){ |
| | | // 先判断是否已经调价过了 |
| | | Object userDynamicPriceObj = redisService.getCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid); |
| | | if(userDynamicPriceObj!=null){ |
| | | // 是否调价过了 |
| | | priceRate = Double.parseDouble(userDynamicPriceObj.toString()); |
| | | }else { |
| | | // 没有调过 |
| | | //是否触发动态调价 redis获取 |
| | | Object dynamicPriceObj = redisService.getCacheObject("DYNAMIC_PRICE_" + openCityId); |
| | | if(dynamicPriceObj!=null){ |
| | | JSONObject jsonObject = JSONObject.parseObject(dynamicPricingJson); |
| | | // 触发动态调价 |
| | | // value=时间 |
| | | String timeStr = dynamicPriceObj.toString(); |
| | | // 判断当前距离这个时间范围的新增订单数(排除取消) / 上浮数量 算出应该增加的价格率 |
| | | R<Integer> r = xpOrderClient.getOrderNum(timeStr); |
| | | if(r.getData()==200){ |
| | | int num = r.getData(); |
| | | // X单上升一次调价 |
| | | Integer orderNum = getOrderNum(jsonObject, 4); |
| | | // 需要调价的次数 |
| | | int count = num / orderNum; |
| | | if(count>0){ |
| | | // 计算每次上升的费率 |
| | | Integer upRate = getOrderNum(jsonObject, 5); |
| | | BigDecimal divide = new BigDecimal(upRate).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); |
| | | for (int i = count; i > 0; i--) { |
| | | // 当前费率+(费率*上升百分比) |
| | | priceRate = new BigDecimal(priceRate).multiply(divide).add(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); |
| | | } |
| | | |
| | | // 冷却时间 |
| | | Integer time = getOrderNum(jsonObject, 6); |
| | | // 触发调价了 |
| | | redisService.setCacheObject("USER_DYNAMIC_PRICE_" + openCityId + "_" + uid, priceRate,time.longValue(), TimeUnit.MINUTES); |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | XpPricingCardVo xpPricingCardVo = new XpPricingCardVo(); |
| | | double amount = 0; |
| | | //等待费 |
| | |
| | | } |
| | | |
| | | // 订单总额 |
| | | Double startPrice = xpPricingCardVo.getStartPrice(); |
| | | // 先减去起步价重新计算 |
| | | amount = amount - startPrice; |
| | | // 动态计算费用 |
| | | startPrice= new BigDecimal(startPrice).multiply(new BigDecimal(priceRate)).setScale(2, RoundingMode.HALF_UP).doubleValue(); |
| | | amount = amount+startPrice; |
| | | xpPricingCardVo.setTotalPrice(amount); |
| | | |
| | | |
| | | return xpPricingCardVo; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取配置 4每X单 5上升X% 6冷却 |
| | | * |
| | | * @param rule |
| | | * @param num |
| | | * @return |
| | | */ |
| | | private Integer getOrderNum(JSONObject rule, int num) { |
| | | Integer param = rule.getInteger("num" + num); |
| | | return param; |
| | | } |
| | | } |