OrderScheduler.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. package com.sqx.scheduler.order;
  2. import cn.hutool.core.collection.CollUtil;
  3. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  4. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  5. import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
  6. import com.ekyong.www.pay.pay.qrcode.api.RhtQrcodePayApi;
  7. import com.ekyong.www.pay.pay.qrcode.bean.QrcodeQueryRequestBean;
  8. import com.ekyong.www.pay.pay.qrcode.bean.QrcodeQueryResponseBean;
  9. import com.github.wxpay.sdk.WXPay;
  10. import com.sqx.modules.common.entity.CommonInfo;
  11. import com.sqx.modules.common.service.CommonInfoService;
  12. import com.sqx.modules.order.entity.TbOrder;
  13. import com.sqx.modules.order.service.AppOrderService;
  14. import com.sqx.modules.pay.config.WXConfig;
  15. import com.sqx.modules.pay.config.WechatPayConfig;
  16. import com.sqx.scheduler.config.SchedulerLock;
  17. import lombok.RequiredArgsConstructor;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.redisson.api.RLock;
  20. import org.redisson.api.RedissonClient;
  21. import org.springframework.scheduling.annotation.Async;
  22. import org.springframework.scheduling.annotation.Scheduled;
  23. import org.springframework.stereotype.Component;
  24. import java.time.LocalDateTime;
  25. import java.time.format.DateTimeFormatter;
  26. import java.util.*;
  27. import java.util.stream.Collectors;
  28. /**
  29. * 订单定时任务
  30. *
  31. * @author : codingliang
  32. * @date : 2024-08-19 20:42
  33. */
  34. @Slf4j
  35. @Component
  36. @RequiredArgsConstructor
  37. public class OrderScheduler {
  38. private final RedissonClient redissonClient;
  39. private final AppOrderService orderService;
  40. private final CommonInfoService commonInfoService;
  41. private final static String RHT_PAY_BASE_URL = "https://api.ekbuyclub.com";
  42. /**
  43. * 预约订单自动接单
  44. * 5分钟运行一次
  45. */
  46. @Async
  47. @Scheduled(cron = "0 */5 * * * ?")
  48. public void reservationAutoReceivingOrder() {
  49. RLock lock = redissonClient.getLock(SchedulerLock.ORDER_OF_RESERVATION_AUTO_RECEIVING_LOCK);
  50. lock.lock();
  51. try {
  52. log.info("预约订单自动接单任务开始运行");
  53. List<Long> orderIds = orderService.getCurWaitReceivingOrderIds();
  54. if (CollUtil.isEmpty(orderIds)) {
  55. log.info("没有符合条件的预约订单,预约订单自动接单任务运行....");
  56. return;
  57. }
  58. List<TbOrder> waitOrders = orderIds.stream().map(orderId -> {
  59. TbOrder waitOrder = new TbOrder();
  60. waitOrder.setOrderId(orderId);
  61. waitOrder.setStatus(6);
  62. return waitOrder;
  63. }).collect(Collectors.toList());
  64. for (TbOrder waitOrder : waitOrders) {
  65. log.info("预约订单id:{},正在自动接单", waitOrder.getOrderId());
  66. try {
  67. orderService.updateOrder(waitOrder);
  68. log.info("预约订单id:{},自动接单成功", waitOrder.getOrderId());
  69. } catch (Exception e) {
  70. e.printStackTrace();
  71. log.error("预约单id:{},自动接单失败,失败原因:{}", waitOrder.getOrderId(), e.getMessage());
  72. }
  73. }
  74. log.info("预约订单自动接单任务运行成功");
  75. } catch (Exception e) {
  76. log.error("预约订单自动接单任务运行失败失败原因:{}", e.getMessage());
  77. } finally {
  78. lock.unlock();
  79. }
  80. }
  81. /**
  82. * 制作中订单自动制作完成
  83. * 每分钟30秒时运行一次
  84. */
  85. @Async
  86. @Scheduled(cron = "30 */2 * * * ?")
  87. public void prodIngOrderAutoCompleted(){
  88. try {
  89. log.info("自动制作完成制作中订单任务开始运行");
  90. // 获取配置:是否开启制作中订单自动完成
  91. String value = commonInfoService.findOne(418).getValue();
  92. if("是".equals(value)){
  93. String minute = commonInfoService.findOne(419).getValue();
  94. LocalDateTime minusMinutes = LocalDateTime.now().minusMinutes(Long.valueOf(minute));
  95. // 获取制作中状态的订单列表
  96. List<TbOrder> orders = orderService.getProdIngOrders(minusMinutes);
  97. if (CollUtil.isEmpty(orders)) {
  98. log.info("当前时间段没有需要自动制作完成的订单");
  99. } else {
  100. // 订单随机排序
  101. Collections.shuffle(orders);
  102. for (TbOrder order: orders){
  103. try {
  104. log.info("订单:{},开始自动制作完成", order.getOrderId());
  105. order.setStatus(3);
  106. orderService.updateOrder(order);
  107. log.info("订单:{},自动制作完成", order.getOrderId());
  108. } catch (Exception e){
  109. e.printStackTrace();
  110. log.error("订单:{},自动完成异常,异常原因:【{}】", order.getOrderId(), e);
  111. }
  112. }
  113. }
  114. }
  115. log.info("自动制作完成制作中订单任务运行成功");
  116. } catch (Exception e) {
  117. log.error("制作中订单自动制作完成任务运行失败失败原因:【{}】", e);
  118. }
  119. }
  120. /**
  121. * 自动完成订单
  122. * 每30s运行一次
  123. */
  124. @Async
  125. @Scheduled(cron = "45 */1 * * * ?")
  126. public void autoFinishOrder() {
  127. RLock lock = redissonClient.getLock(SchedulerLock.ORDER_OF_WAIT_DELIVERY_AUTO_FINISH_LOCK);
  128. lock.lock();
  129. try {
  130. log.info("自动完成订单任务开始运行");
  131. CommonInfo one = commonInfoService.findOne(268);
  132. DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  133. // 查询所有 待取餐/派送中 状态的订单
  134. QueryWrapper<TbOrder> queryWrapper = new QueryWrapper<>();
  135. queryWrapper.eq("status", 3);
  136. List<TbOrder> orders = orderService.list(queryWrapper);
  137. for (TbOrder order: orders) {
  138. try {
  139. LocalDateTime updateTime = LocalDateTime.parse(order.getUpdateTime(), df);
  140. // 计算当前订单什么时候超时完成
  141. LocalDateTime overDateTime = updateTime.plusHours(Integer.parseInt(one.getValue()));
  142. if (LocalDateTime.now().isAfter(overDateTime)) {
  143. log.info("订单id:{},开始自动完成", order.getOrderId());
  144. orderService.accomplishOrders(order.getOrderId(),2);
  145. log.info("订单id:{},完成自动完成", order.getOrderId());
  146. }
  147. } catch (Exception e) {
  148. log.error("订单id:{},开始自动完成失败,失败原因【{}】", order.getOrderId(), e);
  149. }
  150. }
  151. log.info("自动完成订单任务运行成功");
  152. } catch (Exception e) {
  153. log.info("自动完成订单任务运行异常,异常", e);
  154. } finally {
  155. lock.unlock();
  156. }
  157. }
  158. /**
  159. * 自动更改超时订单
  160. * 每3分钟运行一次
  161. */
  162. @Async
  163. @Scheduled(cron = "0 */3 * * * ?")
  164. public void changeTimeOutOrder() {
  165. RLock lock = redissonClient.getLock(SchedulerLock.TIME_OUT_LOCK);
  166. lock.lock();
  167. try {
  168. log.info("超时订单自动取消任务开始运行");
  169. long time = new Date().getTime();
  170. List<TbOrder> orderList = orderService.changeTimeOutOrder(time);
  171. if (orderList.size() == 0) {
  172. log.info("没有符合条件的超时订单,超时订单自动取消任务运行....");
  173. return;
  174. }
  175. WXConfig config = new WXConfig();
  176. // 当前都是小程序支付
  177. config.setAppId(commonInfoService.findOne(74).getValue());
  178. //微信商户key
  179. config.setKey(commonInfoService.findOne(250).getValue());
  180. //微信商户号mchId
  181. config.setMchId(commonInfoService.findOne(251).getValue());
  182. WXPay wxpay = new WXPay(config);
  183. WechatPayConfig wechatMchConfig = WechatPayConfig.builder()
  184. .appId(commonInfoService.findOne(45).getValue())
  185. .mchId(commonInfoService.findOne(434).getValue())
  186. .mchKey(commonInfoService.findOne(435).getValue())
  187. .h5Url(commonInfoService.findOne(19).getValue())
  188. .build();
  189. RhtQrcodePayApi qrcodePay = new RhtQrcodePayApi(wechatMchConfig.getMchId(), wechatMchConfig.getMchKey(), RHT_PAY_BASE_URL);
  190. ArrayList<TbOrder> orders = new ArrayList<>();
  191. for (TbOrder tbOrder : orderList) {
  192. Integer state = tbOrder.getState();
  193. if (0 == state) {
  194. // 状态为待支付需要调用支付系统订单查询接口判断支付系统对应的订单状态
  195. Map<String, String> data = new HashMap<>();
  196. String orderNumber = tbOrder.getOrderNumber();
  197. //商户订单号
  198. data.put("out_trade_no", orderNumber);
  199. Map<String, String> response = wxpay.orderQuery(data);
  200. String trade_state = response.get("trade_state");
  201. //SUCCESS—支付成功,REFUND—转入退款,NOTPAY—未支付,CLOSED—已关闭,REVOKED—已撤销(刷卡支付),USERPAYING--用户支付中,PAYERROR--支付失败(其他原因,如银行返回失败)
  202. if (ObjectUtils.isNotEmpty(trade_state)) {
  203. if ("NOTPAY".equals(trade_state)) {
  204. tbOrder.setStatus(5);
  205. orders.add(tbOrder);
  206. }else if ("SUCCESS".equals(trade_state)){
  207. orderService.updateOrderAfterPaySuccess(tbOrder);
  208. }
  209. }else {
  210. QrcodeQueryRequestBean qqrb = new QrcodeQueryRequestBean();
  211. qqrb.setTraceno(orderNumber);// 商户流水号
  212. QrcodeQueryResponseBean response2 = qrcodePay.query(qqrb);
  213. String respCode = response2.getRespCode();
  214. // 0未支付,1支付成功,2支付失败,4退款中,5退款成功,6退款失败
  215. if ("0".equals(respCode)) {
  216. tbOrder.setStatus(5);
  217. orders.add(tbOrder);
  218. }else if ("1".equals(respCode)){
  219. orderService.updateOrderAfterPaySuccess(tbOrder);
  220. }
  221. }
  222. } else {
  223. tbOrder.setStatus(5);
  224. orders.add(tbOrder);
  225. }
  226. }
  227. orderService.updateBatchById(orders);
  228. log.info("超时订单自动取消运行成功");
  229. } catch (Exception e) {
  230. log.error("超时订单自动取消任务运行失败失败原因:{}", e.getMessage());
  231. } finally {
  232. lock.unlock();
  233. }
  234. }
  235. }