DeliveryOrderNotificationService.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. package com.ruoyi.app.order;
  2. import com.ruoyi.app.order.dto.OrderPushBodyDto;
  3. import com.ruoyi.app.push.BusinessPushProperties;
  4. import com.ruoyi.app.push.NativeRiderBatchPushService;
  5. import com.ruoyi.app.push.UserNotificationScene;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import com.ruoyi.app.utils.PayPush;
  9. import com.ruoyi.app.utils.event.PushEventService;
  10. import com.ruoyi.framework.manager.AsyncManager;
  11. import com.ruoyi.system.domain.InfoUser;
  12. import com.ruoyi.system.domain.PosOrder;
  13. import com.ruoyi.system.domain.RiderPosition;
  14. import com.ruoyi.system.mapper.RiderPositionMapper;
  15. import com.ruoyi.system.service.IInfoUserService;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.stereotype.Service;
  18. import org.springframework.transaction.support.TransactionSynchronization;
  19. import org.springframework.transaction.support.TransactionSynchronizationManager;
  20. import java.util.LinkedHashSet;
  21. import java.util.List;
  22. import java.util.Set;
  23. import java.util.TimerTask;
  24. /** 外送订单开放接单及取消后的推送。 */
  25. @Service
  26. public class DeliveryOrderNotificationService {
  27. private static final Logger log = LoggerFactory.getLogger(DeliveryOrderNotificationService.class);
  28. private static final int RIDER_NOTIFICATION_LIMIT = 20;
  29. private final RiderPositionMapper riderPositionMapper;
  30. private final PushEventService pushEventService;
  31. private final IInfoUserService infoUserService;
  32. private final MerchantNotificationRouter merchantNotificationRouter;
  33. private final BusinessPushProperties pushProperties;
  34. private final NativeRiderBatchPushService nativeRiderBatch;
  35. public DeliveryOrderNotificationService(RiderPositionMapper riderPositionMapper,
  36. PushEventService pushEventService) {
  37. this(riderPositionMapper, pushEventService, null, null);
  38. }
  39. public DeliveryOrderNotificationService(RiderPositionMapper riderPositionMapper,
  40. PushEventService pushEventService,
  41. IInfoUserService infoUserService) {
  42. this(riderPositionMapper, pushEventService, infoUserService, null);
  43. }
  44. public DeliveryOrderNotificationService(RiderPositionMapper riderPositionMapper,
  45. PushEventService pushEventService,
  46. IInfoUserService infoUserService,
  47. MerchantNotificationRouter merchantNotificationRouter) {
  48. this(riderPositionMapper, pushEventService, infoUserService, merchantNotificationRouter, null, null);
  49. }
  50. @Autowired
  51. public DeliveryOrderNotificationService(RiderPositionMapper riderPositionMapper,
  52. PushEventService pushEventService,
  53. IInfoUserService infoUserService,
  54. MerchantNotificationRouter merchantNotificationRouter,
  55. BusinessPushProperties pushProperties,
  56. NativeRiderBatchPushService nativeRiderBatch) {
  57. this.riderPositionMapper = riderPositionMapper;
  58. this.pushEventService = pushEventService;
  59. this.infoUserService = infoUserService;
  60. this.merchantNotificationRouter = merchantNotificationRouter;
  61. this.pushProperties = pushProperties;
  62. this.nativeRiderBatch = nativeRiderBatch;
  63. }
  64. /**
  65. * 支付完成后的新外送订单通知:自配送订单通知商家,其余订单通知附近可接单骑手。
  66. * 所有下单、支付回调与线下转账确认入口复用这里,避免遗漏自配送分流。
  67. */
  68. public void notifyOrderAvailable(PosOrder order) {
  69. if (isAvailableForSelfDeliveryMerchant(order)) {
  70. notifySelfDeliveryOrderToMerchant(order);
  71. return;
  72. }
  73. if (!isAvailableForRider(order)) {
  74. return;
  75. }
  76. runAfterCommit(() -> {
  77. List<RiderPosition> riders = riderPositionMapper.getAcceptRiderList(
  78. order.getLongitude(), order.getLatitude(), RIDER_NOTIFICATION_LIMIT);
  79. if (riders != null) {
  80. if (pushProperties != null && pushProperties.getMode() == BusinessPushProperties.Mode.NATIVE
  81. && nativeRiderBatch != null) {
  82. String ddId = String.valueOf(order.getDdId());
  83. String body = OrderPushBodyDto.getJson(ddId, String.valueOf(order.getState()), 0);
  84. nativeRiderBatch.sendNewOrder(riders, "no.message.push.message",
  85. "no.message.push.new.food.order", body, ddId,
  86. rider -> sendAvailableOrderToRider(rider, order));
  87. } else {
  88. riders.forEach(rider -> sendAvailableOrderToRider(rider, order));
  89. }
  90. }
  91. });
  92. }
  93. /** 外送订单取消后,通知除取消人外的相关方。 */
  94. public void notifyOrderCancelled(PosOrder order, Long operatorId) {
  95. notifyOrderCancelled(order, operatorId, false);
  96. }
  97. public void notifyNoRiderCancelled(PosOrder order) {
  98. notifyOrderCancelled(order, null, true);
  99. }
  100. private void notifyOrderCancelled(PosOrder order, Long operatorId, boolean noRiderTimeout) {
  101. if (order == null || !Long.valueOf(0L).equals(order.getType())
  102. || infoUserService == null) {
  103. return;
  104. }
  105. runAfterCommit(() -> {
  106. Set<Long> recipientIds = new LinkedHashSet<>();
  107. recipientIds.add(order.getUserId());
  108. recipientIds.add(order.getQsId());
  109. if (merchantNotificationRouter == null) {
  110. recipientIds.add(order.getShId());
  111. }
  112. recipientIds.remove(null);
  113. recipientIds.remove(operatorId);
  114. if (recipientIds.isEmpty()) {
  115. return;
  116. }
  117. List<InfoUser> recipients = infoUserService.listByIds(recipientIds);
  118. if (recipients != null) {
  119. recipients.forEach(recipient -> sendCancelledOrder(recipient, order, noRiderTimeout));
  120. }
  121. if (merchantNotificationRouter != null && shouldNotifyMerchant(operatorId)) {
  122. String ddId = String.valueOf(order.getDdId());
  123. String body = OrderPushBodyDto.getJson(ddId, "4", 0);
  124. merchantNotificationRouter.sendStoreNotification(order.getMdId(), order.getShId(),
  125. "no.message.push.message", "no.message.push.order.cancelled", body, ddId);
  126. }
  127. });
  128. }
  129. private boolean shouldNotifyMerchant(Long operatorId) {
  130. if (operatorId == null || infoUserService == null) {
  131. return true;
  132. }
  133. InfoUser operator = infoUserService.getById(operatorId);
  134. return operator == null || "0".equals(operator.getUserType()) || "2".equals(operator.getUserType());
  135. }
  136. void sendAvailableOrderToRider(RiderPosition rider, PosOrder order) {
  137. if (rider == null || rider.getRiderId() == null) {
  138. return;
  139. }
  140. String ddId = String.valueOf(order.getDdId());
  141. String body = OrderPushBodyDto.getJson(ddId, String.valueOf(order.getState()), 0);
  142. AsyncManager.me().execute(new TimerTask() {
  143. @Override
  144. public void run() {
  145. PayPush.qsPushHandleLocal(new PayPush(), pushEventService, rider.getRiderId(), rider.getCid(),
  146. "no.message.push.message", "no.message.push.new.food.order", body, "", ddId);
  147. }
  148. });
  149. }
  150. void sendCancelledOrder(InfoUser recipient, PosOrder order) {
  151. sendCancelledOrder(recipient, order, false);
  152. }
  153. private void sendCancelledOrder(InfoUser recipient, PosOrder order, boolean noRiderTimeout) {
  154. if (recipient == null || recipient.getUserId() == null) {
  155. return;
  156. }
  157. String ddId = String.valueOf(order.getDdId());
  158. String body = OrderPushBodyDto.getJson(ddId, "4", 0);
  159. AsyncManager.me().execute(new TimerTask() {
  160. @Override
  161. public void run() {
  162. PayPush push = new PayPush();
  163. if (recipient.getUserId().equals(order.getQsId())) {
  164. PayPush.qsPushHandleLocal(push, pushEventService, recipient.getUserId(), recipient.getCid(),
  165. "no.message.push.message", "no.message.push.order.cancelled", body, "", ddId);
  166. } else if (recipient.getUserId().equals(order.getShId())) {
  167. PayPush.shPushHandleLocal(push, pushEventService, recipient.getUserId(), recipient.getCid(),
  168. "no.message.push.message", "no.message.push.order.cancelled", body, "", ddId);
  169. } else {
  170. // 只有原链路实际通知的用户带场景,取消操作者和非用户通知范围不变。
  171. String userBody = OrderPushBodyDto.getUserJson(ddId, "4", 0, 1,
  172. UserNotificationScene.ORDER_CANCELLED);
  173. String messageKey = noRiderTimeout && "3".equals(order.getPayType())
  174. ? "no.message.push.order.no.rider.line.cancelled"
  175. : "no.message.push.order.cancelled";
  176. PayPush.userPushHandleLocal(push, pushEventService, recipient.getUserId(), recipient.getCid(),
  177. "no.message.push.message", messageKey, userBody, "", ddId);
  178. }
  179. }
  180. });
  181. }
  182. /** 自配送新单只允许通知实际门店及其归属商家,绝不进入骑手通知链路。 */
  183. private void notifySelfDeliveryOrderToMerchant(PosOrder order) {
  184. if (merchantNotificationRouter == null) {
  185. return;
  186. }
  187. runAfterCommit(() -> {
  188. String ddId = String.valueOf(order.getDdId());
  189. String body = OrderPushBodyDto.getJson(ddId, String.valueOf(order.getState()), 0);
  190. merchantNotificationRouter.sendStoreNotification(order.getMdId(), order.getShId(),
  191. "no.message.push.message", "no.message.push.new.order", body, ddId);
  192. });
  193. }
  194. private boolean isAvailableForSelfDeliveryMerchant(PosOrder order) {
  195. return isPaidUnassignedDeliveryOrder(order) && Integer.valueOf(1).equals(order.getSelfDelivery());
  196. }
  197. private boolean isAvailableForRider(PosOrder order) {
  198. return isPaidUnassignedDeliveryOrder(order)
  199. && Boolean.TRUE.equals(order.getIsDisplay())
  200. && !Integer.valueOf(1).equals(order.getSelfDelivery());
  201. }
  202. private boolean isPaidUnassignedDeliveryOrder(PosOrder order) {
  203. return order != null
  204. && Long.valueOf(0L).equals(order.getType())
  205. && Long.valueOf(0L).equals(order.getState())
  206. && Long.valueOf(0L).equals(order.getDeliveryStatus())
  207. && Long.valueOf(1L).equals(order.getPayStatus())
  208. && Long.valueOf(0L).equals(order.getAfterSaleStatus())
  209. && order.getQsId() == null;
  210. }
  211. private static void runAfterCommit(Runnable action) {
  212. // 已提交的取消/开放接单不能被通知准备或调度失败反向影响。
  213. Runnable safeAction = () -> {
  214. try {
  215. action.run();
  216. } catch (Exception exception) {
  217. log.error("外送订单通知准备失败", exception);
  218. }
  219. };
  220. if (!TransactionSynchronizationManager.isSynchronizationActive()) {
  221. safeAction.run();
  222. return;
  223. }
  224. TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  225. @Override
  226. public void afterCommit() {
  227. safeAction.run();
  228. }
  229. });
  230. }
  231. }