| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589 |
- package com.kym.service.impl;
- import cn.dev33.satoken.stp.StpUtil;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.github.pagehelper.PageHelper;
- import com.github.pagehelper.PageInfo;
- import com.github.yulichang.toolkit.JoinWrappers;
- import com.github.yulichang.wrapper.MPJLambdaWrapper;
- import com.kym.common.exception.BusinessException;
- import com.kym.common.utils.CommUtil;
- import com.kym.common.utils.OrderUtils;
- import com.kym.entity.Account;
- import com.kym.entity.ParkingCouponRecord;
- import com.kym.entity.User;
- import com.kym.entity.WashOrder;
- import com.kym.entity.WashStation;
- import com.kym.entity.awoara.OrderInfo;
- import com.kym.entity.common.PageBean;
- import com.kym.entity.common.PageParams;
- import com.kym.entity.queryParams.DeviceQueryParams;
- import com.kym.entity.queryParams.StatQueryParam;
- import com.kym.entity.queryParams.WashOrderQueryParams;
- import com.kym.entity.vo.StationTrendVo;
- import com.kym.entity.vo.WashOrderVo;
- import com.kym.mapper.WashOrderMapper;
- import com.kym.service.AccountService;
- import com.kym.service.OrderSettlementService;
- import com.kym.service.ParkingCouponRecordService;
- import com.kym.service.UserService;
- import com.kym.service.WashOrderService;
- import com.kym.service.WashStationService;
- import com.kym.service.awoara.AwoaraService;
- import com.kym.service.cache.KymCache;
- import com.kym.service.mybatisplus.MyBaseServiceImpl;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.BeanUtils;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.context.annotation.Lazy;
- import org.springframework.stereotype.Service;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.LocalTime;
- import java.time.temporal.TemporalAdjusters;
- import java.util.List;
- import java.util.Map;
- import java.util.UUID;
- import java.util.stream.Collectors;
- /**
- * <p>
- * 洗车订单表 服务实现类
- * </p>
- *
- * @author skyline
- * @since 2024-09-11
- */
- @Slf4j
- @Service
- public class WashOrderServiceImpl extends MyBaseServiceImpl<WashOrderMapper, WashOrder> implements WashOrderService {
- private final AwoaraService awoaraService;
- private final AccountService accountService;
- private final WashStationService washStationService;
- private final UserService userService;
- private final OrderSettlementService orderSettlementService;
- private final ParkingCouponRecordService parkingCouponRecordService;
- @Value("${kym.domain}")
- private String DOMAIN;
- public WashOrderServiceImpl(AwoaraService awoaraService, AccountService accountService,
- @Lazy WashStationService washStationService, UserService userService,
- @Lazy OrderSettlementService orderSettlementService,
- ParkingCouponRecordService parkingCouponRecordService) {
- this.awoaraService = awoaraService;
- this.accountService = accountService;
- this.washStationService = washStationService;
- this.userService = userService;
- this.orderSettlementService = orderSettlementService;
- this.parkingCouponRecordService = parkingCouponRecordService;
- }
- /**
- * 创建订单(启动洗车机)
- *
- * @param params
- * @return
- */
- @Override
- public String createOrder(DeviceQueryParams params) {
- // 校验余额
- var account = accountService.getAccountByUserId(StpUtil.getLoginIdAsLong());
- if (account.getBalance() < Account.MIN_BALANCE) {
- throw new BusinessException("余额不足,请保持余额不低于2元!");
- }
- // 校验用户是否有未完结的订单
- var unfinishedOrder = lambdaQuery()
- .eq(WashOrder::getUserId, StpUtil.getLoginIdAsLong())
- .and(wrapper -> wrapper
- .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
- .or()
- .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付))
- .list();
- if (!unfinishedOrder.isEmpty()) {
- throw new BusinessException("您有未完结的订单!");
- }
- // 检查设备是否有僵死订单(设备显示忙碌但订单实际已超时)
- checkAndResolveStaleOrder(params.getProductKey(), params.getDeviceName());
- var memberName = StpUtil.getSession().getString(User.ST_SESSION_KEY_MOBILE);
- var orderId = OrderUtils.getOrderNo();
- // 请求阿里云lot
- var createOrder = awoaraService.createOrder(params.getProductKey(), params.getDeviceName(),
- orderId,
- memberName,
- account.getBalance(),
- Account.NO_DISCOUNT,
- // 本次开机最大消费金额
- account.getBalance());
- // 首次消费:无归属站点的用户自动归属到当前设备所在站点
- long userId = StpUtil.getLoginIdAsLong();
- var user = userService.getById(userId);
- var userStationId = user != null ? user.getStationId() : null;
- if (CommUtil.isEmptyOrNull(userStationId)) {
- userService.lambdaUpdate()
- .set(User::getStationId, params.getStationId())
- .eq(User::getId, userId)
- .update();
- StpUtil.getSession().set("stationId", params.getStationId());
- KymCache.INSTANCE.putUserId2StationId(Map.of(userId, params.getStationId()));
- userStationId = params.getStationId();
- }
- var washOrder = new WashOrder()
- .setUserId(StpUtil.getLoginIdAsLong())
- .setStationId(params.getStationId())
- .setProductKey(params.getProductKey())
- .setDeviceName(params.getDeviceName())
- .setShortId(KymCache.INSTANCE.getShortIdByProductKeyAndDeviceName(params.getProductKey(), params.getDeviceName()))
- .setOpenType(WashOrder.START_CLOSE_TYPE_网络)
- .setOrderId(orderId)
- .setOrderIdLocal(createOrder.getOrder_id_local())
- .setMemberDiscount(Account.NO_DISCOUNT)
- .setPrepayMoney(account.getBalance())
- .setStartTime(LocalDateTime.now())
- .setOrderStatus(WashOrder.ORDER_STATUS_开机)
- .setPayStatus(WashOrder.PAY_STATUS_未支付)
- .setIsCross(!params.getStationId().equals(userStationId));
- save(washOrder);
- return orderId;
- }
- @Override
- public void closeOrder(DeviceQueryParams params) {
- var order = lambdaQuery()
- .eq(WashOrder::getProductKey, params.getProductKey())
- .eq(WashOrder::getDeviceName, params.getDeviceName())
- .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
- .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
- .one();
- if (order == null) {
- return;
- }
- if (order.getUserId() != StpUtil.getLoginIdAsLong()) {
- throw new BusinessException("您没有权限关闭该订单!");
- }
- // 尝试发送关闭命令,失败后重试1次
- boolean sent = sendCloseOrderWithRetry(params.getProductKey(), params.getDeviceName(), order.getOrderId(), 1);
- if (sent) {
- return;
- }
- // RRpc 失败,主动查询设备订单状态
- log.warn("订单 {} 关闭命令发送失败,尝试主动查询设备状态", order.getOrderId());
- try {
- OrderInfo orderInfo = awoaraService.queryOrder(params.getProductKey(), params.getDeviceName(), order.getOrderId());
- if (orderInfo != null && orderInfo.getClose_type() != null && !orderInfo.getClose_type().isEmpty()) {
- log.info("订单 {} 设备已关闭,执行结算", order.getOrderId());
- orderSettlementService.settleOrder(order, orderInfo);
- return;
- }
- if (orderInfo != null && (orderInfo.getClose_type() == null || orderInfo.getClose_type().isEmpty())) {
- // 设备还在运行,尝试强制关闭
- log.info("订单 {} 设备仍在运行,尝试强制关闭", order.getOrderId());
- try {
- awoaraService.forceCloseOrder(params.getProductKey(), params.getDeviceName());
- } catch (Exception fe) {
- log.error("订单 {} 强制关闭也失败", order.getOrderId(), fe);
- }
- }
- } catch (Exception e) {
- log.error("订单 {} 主动查询设备状态也失败", order.getOrderId(), e);
- }
- throw new BusinessException("关闭订单失败,请稍后重试或联系管理员");
- }
- @Override
- public void forceSettleOrder(String orderId) {
- var order = lambdaQuery()
- .eq(WashOrder::getOrderId, orderId)
- .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
- .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
- .one();
- if (order == null) {
- throw new BusinessException("未找到该订单或订单已完结");
- }
- // 尝试通过 RRpc 发送关闭命令
- sendCloseOrderWithRetry(order.getProductKey(), order.getDeviceName(), order.getOrderId(), 1);
- // 查询设备订单状态进行结算
- log.info("订单 {} 已发送关闭命令,查询设备订单状态进行结算", order.getOrderId());
- try {
- OrderInfo orderInfo = awoaraService.queryOrder(order.getProductKey(), order.getDeviceName(), order.getOrderId());
- if (orderInfo != null && orderInfo.getClose_type() != null && !orderInfo.getClose_type().isEmpty()) {
- log.info("订单 {} 设备已关闭,执行结算", order.getOrderId());
- orderSettlementService.settleOrder(order, orderInfo);
- return;
- }
- if (orderInfo != null && (orderInfo.getClose_type() == null || orderInfo.getClose_type().isEmpty())) {
- // 设备还在运行,尝试强制关闭
- log.info("订单 {} 设备仍在运行,尝试强制关闭", order.getOrderId());
- try {
- awoaraService.forceCloseOrder(order.getProductKey(), order.getDeviceName());
- } catch (Exception fe) {
- log.error("订单 {} 强制关闭也失败", order.getOrderId(), fe);
- }
- }
- } catch (Exception e) {
- log.error("订单 {} 主动查询设备状态也失败", order.getOrderId(), e);
- }
- throw new BusinessException("强制结算失败,请稍后重试或联系管理员");
- }
- private boolean sendCloseOrderWithRetry(String productKey, String deviceName, String orderId, int maxRetries) {
- for (int i = 0; i <= maxRetries; i++) {
- try {
- awoaraService.closeOrder(productKey, deviceName, orderId);
- return true;
- } catch (Exception e) {
- if (i < maxRetries) {
- log.warn("订单 {} 关闭命令第{}次失败,准备重试", orderId, i + 1, e);
- } else {
- log.error("订单 {} 关闭命令{}次均失败", orderId, maxRetries + 1, e);
- }
- }
- }
- return false;
- }
- /**
- * 检查设备是否有僵死订单,有则尝试清理
- */
- private void checkAndResolveStaleOrder(String productKey, String deviceName) {
- var staleOrder = lambdaQuery()
- .eq(WashOrder::getProductKey, productKey)
- .eq(WashOrder::getDeviceName, deviceName)
- .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
- .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
- .one();
- if (staleOrder == null) {
- return;
- }
- log.warn("设备 {}/{} 存在未完结订单 {},尝试查询设备实际状态", productKey, deviceName, staleOrder.getOrderId());
- try {
- OrderInfo orderInfo = awoaraService.queryOrder(productKey, deviceName, staleOrder.getOrderId());
- if (orderInfo != null && orderInfo.getClose_type() != null && !orderInfo.getClose_type().isEmpty()) {
- log.info("设备实际已关闭订单 {},执行结算", staleOrder.getOrderId());
- orderSettlementService.settleOrder(staleOrder, orderInfo);
- }
- } catch (Exception e) {
- log.warn("查询设备订单状态失败,跳过清理:{}", e.getMessage());
- }
- }
- /**
- * 查询订单详情
- *
- * @param params
- * @return
- */
- @Override
- public WashOrder queryOrder(WashOrderQueryParams params) {
- // 非实时数据
- WashOrder order = lambdaQuery()
- .eq(WashOrder::getOrderId, params.getOrderId())
- .one();
- if (null != params.getUserId()) {
- CommUtil.asserts(null != order && order.getUserId().equals(StpUtil.getLoginIdAsLong()),
- "订单不存在或您没有权限查看该订单!");
- }
- return order;
- }
- /**
- * 查询停车减免订单
- *
- * @param unionid
- * @return
- */
- @Override
- public String getParkingDiscounts(String unionid) {
- var user = userService.lambdaQuery().eq(User::getUnionid, unionid).one();
- CommUtil.asserts(null != user, "用户信息异常:无此用户");
- // 查询用户24小时内的订单
- var orders = lambdaQuery()
- .eq(WashOrder::getUserId, user.getId())
- .ge(WashOrder::getStartTime, LocalDateTime.now().minusHours(24))
- .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_已支付)
- .orderByDesc(WashOrder::getId)
- .list();
- CommUtil.asserts(CommUtil.isEmptyOrNull(orders) && (orders.stream().mapToInt(WashOrder::getAmount).sum() >= 0),
- "抱歉:无停车场洗车记录");
- return washStationService.lambdaQuery().eq(WashStation::getStationId, orders.get(0).getStationId()).one().getParkingQrCode();
- }
- /**
- * 当前用户订单列表
- *
- * @param params
- * @return
- */
- @Override
- public PageBean<WashOrderVo> listMyWashOrder(PageParams params) {
- PageHelper.startPage(params.getPageNum(), params.getPageSize());
- var res = lambdaQuery()
- .eq(WashOrder::getUserId, StpUtil.getLoginIdAsLong())
- .orderByDesc(WashOrder::getId)
- .list();
- PageInfo<WashOrder> pages = new PageInfo<>(res);
- var voList = pages.getList().stream().map(order -> {
- var vo = new WashOrderVo();
- BeanUtils.copyProperties(order, vo);
- vo.setStationName(KymCache.INSTANCE.getStationNameById(order.getStationId()));
- return vo;
- }).toList();
- PageBean<WashOrderVo> bean = new PageBean<>(voList);
- bean.setPages(pages.getPages());
- bean.setPageNum(pages.getPageNum());
- bean.setPageSize(pages.getPageSize());
- bean.setTotal(pages.getTotal());
- return bean;
- }
- //region 管理后台
- @Override
- public PageBean<WashOrderVo> list(WashOrderQueryParams params) {
- PageHelper.startPage(params.getPageNum(), params.getPageSize());
- MPJLambdaWrapper<WashOrder> wrapper = JoinWrappers.lambda(WashOrder.class)
- .selectAsClass(WashOrder.class, WashOrderVo.class)
- .selectAs(User::getMobilePhone, WashOrderVo::getMobilePhone)
- .leftJoin(User.class, User::getId, WashOrder::getUserId)
- .eq(CommUtil.isNotEmptyAndNull(params.getUserId()), WashOrder::getUserId, params.getUserId())
- .eq(CommUtil.isNotEmptyAndNull(params.getMobilePhone()), User::getMobilePhone, params.getMobilePhone())
- .eq(CommUtil.isNotEmptyAndNull(params.getOrderStatus()), WashOrder::getOrderStatus, params.getOrderStatus())
- .eq(CommUtil.isNotEmptyAndNull(params.getPayStatus()), WashOrder::getPayStatus, params.getPayStatus())
- .orderByDesc(WashOrder::getId);
- //连表查询 返回自定义ResultType
- List<WashOrderVo> list = selectJoinList(WashOrderVo.class, wrapper);
- list.forEach(item -> {
- item.setStationName(KymCache.INSTANCE.getStationNameById(item.getStationId()));
- item.setUserStationId(KymCache.INSTANCE.getUserStationId(item.getUserId()));
- item.setUserStationName(KymCache.INSTANCE.getStationNameById(item.getUserStationId()));
- });
- return new PageBean<>(list);
- }
- /**
- * 获取订单详情
- * 根据订单号查询,而不是主键ID
- *
- * @param orderId 订单号
- * @return 订单详情
- */
- @Override
- public WashOrderVo detail(String orderId) {
- MPJLambdaWrapper<WashOrder> wrapper = JoinWrappers.lambda(WashOrder.class)
- .selectAsClass(WashOrder.class, WashOrderVo.class)
- .selectAs(User::getMobilePhone, WashOrderVo::getMobilePhone)
- .leftJoin(User.class, User::getId, WashOrder::getUserId)
- .eq(WashOrder::getOrderId, orderId);
- WashOrderVo washOrderVo = selectJoinOne(WashOrderVo.class, wrapper);
- if (washOrderVo != null) {
- washOrderVo.setStationName(KymCache.INSTANCE.getStationNameById(washOrderVo.getStationId()));
- washOrderVo.setUserStationId(KymCache.INSTANCE.getUserStationId(washOrderVo.getUserId()));
- washOrderVo.setUserStationName(KymCache.INSTANCE.getStationNameById(washOrderVo.getUserStationId()));
- }
- return washOrderVo;
- }
- /**
- * 统计指定日期各站点消费金额
- *
- * @param statDay
- * @return
- */
- @Override
- public Map<String, Integer> sumAmountByDate(LocalDate statDay) {
- LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
- wrapper.select(WashOrder::getAmount, WashOrder::getStationId);
- wrapper.ge(WashOrder::getStartTime, LocalDateTime.of(statDay, LocalTime.MIN));
- wrapper.gt(WashOrder::getStartTime, LocalDateTime.of(statDay, LocalTime.MAX));
- var list = list(wrapper);
- // 按照站点分组统计金额
- return list.stream().collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(WashOrder::getAmount)));
- }
- /**
- * 统计指定日期当月各站点总消费金额
- *
- * @param statDay
- * @return
- */
- @Override
- public Map<String, Integer> sumMonthAmount(LocalDate statDay) {
- var startTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).atTime(LocalTime.MIN);
- var endTime = statDay.with(TemporalAdjusters.lastDayOfMonth()).atTime(LocalTime.MAX);
- LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
- wrapper.select(WashOrder::getAmount, WashOrder::getStationId);
- wrapper.ge(WashOrder::getStartTime, startTime);
- wrapper.lt(WashOrder::getStartTime, endTime);
- var list = list(wrapper);
- // 按照站点分组统计金额
- return list.stream().collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(WashOrder::getAmount)));
- }
- /**
- * 统计指定日期订单数量
- *
- * @param statDay
- * @return
- */
- @Override
- public Map<String, Integer> countDailyOrders(LocalDate statDay) {
- LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
- wrapper.ge(WashOrder::getStartTime, LocalDateTime.of(statDay, LocalTime.MIN));
- wrapper.lt(WashOrder::getStartTime, LocalDateTime.of(statDay, LocalTime.MAX));
- // 按照站点分组统计订单数量
- return list(wrapper).stream().collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(o -> 1)));
- }
- /**
- * 统计指定日期订单数量
- *
- * @param statDay
- * @return
- */
- @Override
- public Map<String, Integer> countMonthOrders(LocalDate statDay) {
- var startTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).atTime(LocalTime.MIN);
- var endTime = statDay.with(TemporalAdjusters.lastDayOfMonth()).atTime(LocalTime.MAX);
- LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
- wrapper.select(WashOrder::getStationId);
- wrapper.ge(WashOrder::getStartTime, startTime);
- wrapper.lt(WashOrder::getStartTime, endTime);
- // 按照站点分组统计订单数量
- return list(wrapper).stream().collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(o -> 1)));
- }
- @Override
- public Map<String, Integer> countDailyActiveUsers(LocalDate statDay) {
- LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
- wrapper.select(WashOrder::getUserId, WashOrder::getStationId);
- wrapper.ge(WashOrder::getStartTime, LocalDateTime.of(statDay, LocalTime.MIN));
- wrapper.lt(WashOrder::getStartTime, LocalDateTime.of(statDay, LocalTime.MAX));
- wrapper.groupBy(WashOrder::getStationId, WashOrder::getUserId);
- return list(wrapper).stream()
- .collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(o -> 1)));
- }
- @Override
- public Map<String, Integer> countMonthActiveUsers(LocalDate statDay) {
- var startTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).atTime(LocalTime.MIN);
- var endTime = statDay.with(TemporalAdjusters.lastDayOfMonth()).atTime(LocalTime.MAX);
- LambdaQueryWrapper<WashOrder> wrapper = new LambdaQueryWrapper<>();
- wrapper.select(WashOrder::getUserId, WashOrder::getStationId);
- wrapper.ge(WashOrder::getStartTime, startTime);
- wrapper.lt(WashOrder::getStartTime, endTime);
- wrapper.groupBy(WashOrder::getStationId, WashOrder::getUserId);
- return list(wrapper).stream()
- .collect(Collectors.groupingBy(WashOrder::getStationId, Collectors.summingInt(o -> 1)));
- }
- @Override
- public WashOrder getOrderInProgressByUserId(long userId) {
- return lambdaQuery()
- .eq(WashOrder::getUserId, userId)
- .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
- .one();
- }
- @Override
- public List<StationTrendVo> stationTrend(StatQueryParam params) {
- return baseMapper.StationTrend(params);
- }
- @Override
- public String checkParkingCoupon(String mobilePhone) {
- CommUtil.asserts(CommUtil.isNotEmptyAndNull(mobilePhone),"查询手机号不能为空");
- var user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getMobilePhone, mobilePhone));
- if (user == null) {
- throw new BusinessException("请输入注册洗车小程序使用的手机号码!");
- }
- // 优惠券有效期2小时,先查已支付订单
- var orderList = lambdaQuery()
- .eq(WashOrder::getUserId, user.getId())
- .ge(WashOrder::getEndTime, LocalDateTime.now().minusHours(2))
- .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_已支付)
- .orderByDesc(WashOrder::getId).list();
- if (!orderList.isEmpty() && orderList.stream().collect(Collectors.summarizingInt(WashOrder::getAmount)).getSum() >= KymCache.INSTANCE.getParkingCouponMinAmountByStationId(orderList.get(0).getStationId())) {
- var parkingCouponUrl = KymCache.INSTANCE.getParkingQrCodeUrlByStationId(orderList.get(0).getStationId());
- var code = UUID.randomUUID().toString();
- KymCache.INSTANCE.setParkingCouponCode(code, parkingCouponUrl, 3600 * 2L);
- parkingCouponRecordService.save(new ParkingCouponRecord()
- .setCode(code)
- .setUserId(user.getId())
- .setStationId(orderList.get(0).getStationId())
- .setOrderId(orderList.get(0).getOrderId())
- .setTargetUrl(parkingCouponUrl)
- .setStatus(ParkingCouponRecord.STATUS_未使用)
- .setExpireTime(LocalDateTime.now().plusHours(2)));
- return DOMAIN + "/api/parking-coupon?code=" + code;
- }
- // 未找到符合条件的已支付订单,尝试查找僵死订单并主动对账结算
- var staleOrders = lambdaQuery()
- .eq(WashOrder::getUserId, user.getId())
- .ge(WashOrder::getStartTime, LocalDateTime.now().minusHours(2))
- .eq(WashOrder::getOrderStatus, WashOrder.ORDER_STATUS_开机)
- .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_未支付)
- .orderByDesc(WashOrder::getId).list();
- if (!staleOrders.isEmpty()) {
- boolean reconciled = false;
- for (WashOrder staleOrder : staleOrders) {
- try {
- OrderInfo orderInfo = awoaraService.queryOrder(staleOrder.getProductKey(), staleOrder.getDeviceName(), staleOrder.getOrderId());
- if (orderInfo != null && orderInfo.getClose_type() != null && !orderInfo.getClose_type().isEmpty()) {
- log.info("停车券查询-订单 {} 设备已关闭,主动结算", staleOrder.getOrderId());
- orderSettlementService.settleOrder(staleOrder, orderInfo);
- reconciled = true;
- }
- } catch (Exception e) {
- log.warn("停车券查询-订单 {} 查询设备失败:{}", staleOrder.getOrderId(), e.getMessage());
- }
- }
- if (reconciled) {
- // 结算后重新查询已支付订单
- orderList = lambdaQuery()
- .eq(WashOrder::getUserId, user.getId())
- .ge(WashOrder::getEndTime, LocalDateTime.now().minusHours(2))
- .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_已支付)
- .orderByDesc(WashOrder::getId).list();
- if (!orderList.isEmpty() && orderList.stream().collect(Collectors.summarizingInt(WashOrder::getAmount)).getSum() >= KymCache.INSTANCE.getParkingCouponMinAmountByStationId(orderList.get(0).getStationId())) {
- var parkingCouponUrl = KymCache.INSTANCE.getParkingQrCodeUrlByStationId(orderList.get(0).getStationId());
- var code = UUID.randomUUID().toString();
- KymCache.INSTANCE.setParkingCouponCode(code, parkingCouponUrl, 3600 * 2L);
- parkingCouponRecordService.save(new ParkingCouponRecord()
- .setCode(code)
- .setUserId(user.getId())
- .setStationId(orderList.get(0).getStationId())
- .setOrderId(orderList.get(0).getOrderId())
- .setTargetUrl(parkingCouponUrl)
- .setStatus(ParkingCouponRecord.STATUS_未使用)
- .setExpireTime(LocalDateTime.now().plusHours(2)));
- return DOMAIN + "/api/parking-coupon?code=" + code;
- }
- }
- }
- throw new BusinessException("不符合优惠条件:订单完成超过2小时或洗车金额不足6元。");
- }
- //endregion
- }
|