PosOrderQsOprateController.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. package com.ruoyi.app.order;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  6. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  7. import com.ruoyi.app.order.dto.OrderPushBodyDto;
  8. import com.ruoyi.app.service.UserService;
  9. import com.ruoyi.app.utils.PayPush;
  10. import com.ruoyi.app.utils.event.PushEventService;
  11. import com.ruoyi.common.annotation.Anonymous;
  12. import com.ruoyi.common.core.controller.BaseController;
  13. import com.ruoyi.common.core.domain.AjaxResult;
  14. import com.ruoyi.common.exception.ServiceException;
  15. import com.ruoyi.common.utils.MessageUtils;
  16. import com.ruoyi.common.utils.StringUtils;
  17. import com.ruoyi.framework.manager.AsyncManager;
  18. import com.ruoyi.system.domain.InfoUser;
  19. import com.ruoyi.system.domain.PosOrder;
  20. import com.ruoyi.system.domain.PosStore;
  21. import com.ruoyi.system.domain.UserBilling;
  22. import com.ruoyi.system.service.IInfoUserService;
  23. import com.ruoyi.system.service.IPosOrderService;
  24. import com.ruoyi.system.service.IPosStoreService;
  25. import com.ruoyi.system.service.IUserBillingService;
  26. import com.ruoyi.system.utils.Auth;
  27. import com.ruoyi.system.utils.JwtUtil;
  28. import org.redisson.api.RLock;
  29. import org.redisson.api.RedissonClient;
  30. import org.springframework.beans.factory.annotation.Autowired;
  31. import org.springframework.context.i18n.LocaleContextHolder;
  32. import org.springframework.transaction.annotation.Transactional;
  33. import org.springframework.transaction.support.TransactionSynchronization;
  34. import org.springframework.transaction.support.TransactionSynchronizationManager;
  35. import org.springframework.web.bind.annotation.*;
  36. import java.util.*;
  37. import java.util.concurrent.TimeUnit;
  38. import java.util.stream.Collectors;
  39. @RestController
  40. @RequestMapping("/system/orderQsOprate")
  41. public class PosOrderQsOprateController extends BaseController {
  42. @Autowired
  43. private IPosOrderService posOrderService;
  44. @Autowired
  45. private IInfoUserService infoUserService;
  46. @Autowired
  47. private PushEventService pushEventService;
  48. @Autowired
  49. private RedissonClient redissonClient;
  50. @Autowired
  51. private UserService userService;
  52. @Autowired
  53. private IUserBillingService userBillingService;
  54. @Autowired
  55. private IPosStoreService posStoreService;
  56. /**
  57. * 骑手接单:校验 type=0 且 afterSaleStatus=0,设置 deliveryStatus=1
  58. */
  59. @Anonymous
  60. @Auth
  61. @PostMapping("/acceptOrder")
  62. @Transactional(rollbackFor = Exception.class)
  63. public AjaxResult acceptOrder(@RequestHeader String token, @RequestParam Long id) {
  64. JwtUtil jwtUtil = new JwtUtil();
  65. PayPush push = new PayPush();
  66. String qsId = jwtUtil.getusid(token);
  67. PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
  68. if (order == null) {
  69. throw new ServiceException(MessageUtils.message("no.order.not.found"));
  70. }
  71. if (order.getType() != null && order.getType() != 0L) {
  72. throw new ServiceException("仅外送订单支持骑手接单");
  73. }
  74. if (order.getAfterSaleStatus() != null && order.getAfterSaleStatus() > 0) {
  75. throw new ServiceException("订单存在售后申请,无法操作");
  76. }
  77. PosOrder posOrder = new PosOrder();
  78. posOrder.setId(order.getId());
  79. posOrder.setDeliveryStatus(1L);
  80. posOrder.setQsId(Long.valueOf(qsId));
  81. return setOrderQsState(posOrder, qsId, push);
  82. }
  83. /**
  84. * 骑手取餐:校验 type=0 且 afterSaleStatus=0,设置 deliveryStatus=2
  85. */
  86. @Anonymous
  87. @Auth
  88. @PostMapping("/pickupOrder")
  89. @Transactional(rollbackFor = Exception.class)
  90. public AjaxResult pickupOrder(@RequestHeader String token, @RequestParam Long id) {
  91. JwtUtil jwtUtil = new JwtUtil();
  92. PayPush push = new PayPush();
  93. String qsId = jwtUtil.getusid(token);
  94. PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
  95. if (order == null) {
  96. throw new ServiceException(MessageUtils.message("no.order.not.found"));
  97. }
  98. if (order.getAfterSaleStatus() != null && order.getAfterSaleStatus() > 0) {
  99. throw new ServiceException("订单存在售后申请,无法操作");
  100. }
  101. PosOrder posOrder = new PosOrder();
  102. posOrder.setId(order.getId());
  103. posOrder.setDeliveryStatus(2L);
  104. return setOrderQsState(posOrder, qsId, push);
  105. }
  106. /**
  107. * 骑手送达:设置 deliveryStatus=3,同时设置 state=3
  108. */
  109. @Anonymous
  110. @Auth
  111. @PostMapping("/deliverOrder")
  112. @Transactional(rollbackFor = Exception.class)
  113. public AjaxResult deliverOrder(@RequestHeader String token, @RequestParam Long id) {
  114. JwtUtil jwtUtil = new JwtUtil();
  115. PayPush push = new PayPush();
  116. String qsId = jwtUtil.getusid(token);
  117. PosOrder order = posOrderService.getOne(new LambdaQueryWrapper<PosOrder>().eq(PosOrder::getId, id));
  118. if (order == null) {
  119. throw new ServiceException(MessageUtils.message("no.order.not.found"));
  120. }
  121. PosOrder posOrder = new PosOrder();
  122. posOrder.setId(order.getId());
  123. posOrder.setDeliveryStatus(3L);
  124. posOrder.setState(3L);
  125. posOrder.setSdTime(new Date());
  126. return setOrderQsState(posOrder, qsId, push);
  127. }
  128. //骑手接单、取餐、送达
  129. private AjaxResult setOrderQsState(PosOrder posOrder, String qsId, PayPush push) {
  130. String lockKey = "order:qs:lock:" + posOrder.getId();
  131. RLock lock = redissonClient.getLock(lockKey);
  132. try {
  133. var local = LocaleContextHolder.getLocale();
  134. logger.info("骑手接单local信息:" + local.getLanguage());
  135. logger.info(JSON.toJSONString(local));
  136. // 尝试获取锁
  137. if (lock.tryLock(20L, 10L, TimeUnit.SECONDS)) {
  138. boolean releaseInfinally = true;
  139. try {
  140. userService.checkUserStatus(Long.valueOf(qsId));
  141. PosOrder orst = posOrderService.getById(posOrder.getId());
  142. if (orst.getDeliveryStatus() != null && orst.getDeliveryStatus() == 1L && posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 1L) {
  143. throw new ServiceException(MessageUtils.message("no.order.snatched"));
  144. }
  145. if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 1L) {
  146. QueryWrapper<PosOrder> wrapper = new QueryWrapper<>();
  147. wrapper.eq("qs_id", qsId);
  148. wrapper.in("delivery_status", 1, 2);
  149. List<PosOrder> orsts = posOrderService.list(wrapper);
  150. if (orsts.size() > 0) {
  151. throw new ServiceException(MessageUtils.message("no.exist.undelivered.order"));
  152. }
  153. }
  154. String userMessage = MessageUtils.message("no.message.push.delivery.personnel.receiving.order");
  155. if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 2L) {
  156. userMessage = MessageUtils.message("no.message.push.delivery.personnel.qspsz.order");
  157. } else if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 3L) {
  158. userMessage = MessageUtils.message("no.message.push.delivery.personnel.qsysd.order");
  159. }
  160. boolean org = posOrderService.saveOrUpdate(posOrder);
  161. if (org) {
  162. //到付订单,骑手送达时设置用户账单为完成
  163. if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 3L && "1".equals(orst.getCollectPayment())) {
  164. updateUserBill(orst.getDdId(), orst.getUserId(), orst.getQsId());
  165. }
  166. InfoUser user = infoUserService.getById(orst.getUserId());
  167. InfoUser shu = infoUserService.getById(orst.getShId());
  168. String finalUserMessage = userMessage;
  169. releaseInfinally = false;
  170. TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  171. @Override
  172. public void afterCommit() {
  173. if (lock.isHeldByCurrentThread()) {
  174. lock.unlock();
  175. }
  176. // 给用户推送(骑手已接单/配送中/已送达)
  177. if (!StringUtils.isEmpty(user.getCid())) {
  178. String userTitle = "no.message.push.message";
  179. String userContent = "no.message.push.delivery.personnel.receiving.order";
  180. if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 2L) {
  181. userContent = "no.message.push.delivery.personnel.qspsz.order";
  182. } else if (posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 3L) {
  183. userContent = "no.message.push.delivery.personnel.qsysd.order";
  184. }
  185. final String finalUserContent = userContent;
  186. String userBody = OrderPushBodyDto.getJson(String.valueOf(orst.getDdId()), String.valueOf(posOrder.getState()));
  187. Long userUserId = user.getUserId();
  188. String userCid = user.getCid();
  189. String userCidType = "";
  190. String userDdId = String.valueOf(orst.getDdId());
  191. AsyncManager.me().execute(new TimerTask() {
  192. @Override
  193. public void run() {
  194. PayPush.userPushHandleLocal(push, pushEventService, userUserId, userCid, userTitle, finalUserContent, userBody, userCidType, userDdId);
  195. }
  196. });
  197. }
  198. // 给商家推送(骑手已接单时)
  199. if (!StringUtils.isEmpty(shu.getCid()) && posOrder.getDeliveryStatus() != null && posOrder.getDeliveryStatus() == 1L) {
  200. String shTitle = "no.message.push.message";
  201. String shContent = "no.message.push.delivery.personnel.receiving.order";
  202. String shBody = OrderPushBodyDto.getJson(String.valueOf(orst.getDdId()), String.valueOf(posOrder.getState()));
  203. Long shUserId = shu.getUserId();
  204. String shCid = shu.getCid();
  205. String shCidType = "";
  206. String shDdId = String.valueOf(orst.getDdId());
  207. AsyncManager.me().execute(new TimerTask() {
  208. @Override
  209. public void run() {
  210. PayPush.shPushHandleLocal(push, pushEventService, shUserId, shCid, shTitle, shContent, shBody, shCidType, shDdId);
  211. }
  212. });
  213. }
  214. }
  215. });
  216. return success(MessageUtils.message("no.modify.success"), posOrder.getId());
  217. } else {
  218. return error();
  219. }
  220. } finally {
  221. if (releaseInfinally && lock.isHeldByCurrentThread()) {
  222. lock.unlock();
  223. }
  224. }
  225. } else {
  226. throw new ServiceException(MessageUtils.message("no.system.busy.try.again"));
  227. }
  228. } catch (InterruptedException e) {
  229. Thread.currentThread().interrupt();
  230. throw new ServiceException(MessageUtils.message("no.operation.interrupted.try.again"));
  231. }
  232. }
  233. /**
  234. * 更新用户用户账单
  235. *
  236. * @param ddId
  237. * @param userId
  238. * @param qsId
  239. */
  240. private void updateUserBill(String ddId, Long userId, Long qsId) {
  241. QueryWrapper<UserBilling> queryWrapper = new QueryWrapper<>();
  242. queryWrapper.eq("dd_id", ddId);
  243. queryWrapper.eq("user_id", userId);
  244. queryWrapper.eq("type", "3");
  245. UserBilling userBill = userBillingService.getOne(queryWrapper);
  246. if (userBill != null) {
  247. userBill.setState("0");
  248. userBill.setIllustrate("Rider Payment Order");
  249. userBill.setBalancePay("1");
  250. userBill.setPaymentId(String.valueOf(qsId));
  251. userBillingService.saveOrUpdate(userBill);
  252. }
  253. }
  254. /**
  255. * 骑手端订单列表(Tab分页)
  256. */
  257. @Anonymous
  258. @Auth
  259. @GetMapping("/orderList")
  260. public AjaxResult orderList(@RequestHeader String token, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size, @RequestParam(required = false) String tab, @RequestParam(required = false) java.math.BigDecimal longitude, @RequestParam(required = false) java.math.BigDecimal latitude) {
  261. JwtUtil jwtUtil = new JwtUtil();
  262. String qsId = jwtUtil.getusid(token);
  263. Long riderId = Long.valueOf(qsId);
  264. LambdaQueryWrapper<PosOrder> wrapper = new LambdaQueryWrapper<>();
  265. wrapper.eq(PosOrder::getIsDisplay,true);
  266. switch (tab) {
  267. case "newTask":
  268. wrapper.eq(PosOrder::getType, 0L).eq(PosOrder::getDeliveryStatus, 0L).eq(PosOrder::getState, 2L).eq(PosOrder::getAfterSaleStatus, 0L);
  269. if (longitude != null && latitude != null) {
  270. wrapper.last("ORDER BY ST_Distance_Sphere(point(longitude, latitude), point(" + longitude + ", " + latitude + ")) ASC");
  271. } else {
  272. wrapper.orderByDesc(PosOrder::getCretim);
  273. }
  274. break;
  275. case "toPickup":
  276. wrapper.eq(PosOrder::getDeliveryStatus, 1L).eq(PosOrder::getQsId, riderId).eq(PosOrder::getAfterSaleStatus, 0L).orderByAsc(PosOrder::getCretim);
  277. break;
  278. case "delivering":
  279. wrapper.eq(PosOrder::getDeliveryStatus, 2L).eq(PosOrder::getQsId, riderId).eq(PosOrder::getAfterSaleStatus, 0L).orderByAsc(PosOrder::getCretim);
  280. break;
  281. case "completed":
  282. wrapper.eq(PosOrder::getState, 3L).eq(PosOrder::getAfterSaleStatus, 0L).eq(PosOrder::getQsId, riderId).orderByDesc(PosOrder::getCretim);
  283. break;
  284. case "cancelled":
  285. wrapper.eq(PosOrder::getState, 4L).eq(PosOrder::getQsId, riderId).eq(PosOrder::getAfterSaleStatus, 0L).orderByDesc(PosOrder::getCretim);
  286. break;
  287. case "refund":
  288. wrapper.gt(PosOrder::getAfterSaleStatus, 0L).eq(PosOrder::getQsId, riderId).orderByDesc(PosOrder::getCretim);
  289. break;
  290. default:
  291. break;
  292. }
  293. com.baomidou.mybatisplus.extension.plugins.pagination.Page<PosOrder> pageParam = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page, size);
  294. com.baomidou.mybatisplus.extension.plugins.pagination.Page<PosOrder> result = posOrderService.page(pageParam, wrapper);
  295. Set<Long> mdIds = result.getRecords().stream().map(PosOrder::getMdId).filter(Objects::nonNull).collect(Collectors.toSet());
  296. Map<Integer, PosStore> storeMap = mdIds.isEmpty() ? Collections.emptyMap() :
  297. posStoreService.listByIds(mdIds).stream().collect(Collectors.toMap(PosStore::getId, s -> s));
  298. JSONArray arr=new JSONArray();
  299. for (PosOrder order : result.getRecords()) {
  300. // 自动序列化所有PosOrder字段,新增字段无需手动添加
  301. JSONObject org = JSON.parseObject(
  302. JSON.toJSONStringWithDateFormat(order, "yyyy-MM-dd HH:mm:ss")
  303. );
  304. // 以下为非PosOrder字段或需要特殊处理的字段
  305. org.put("store", storeMap.get(order.getMdId().intValue()));
  306. arr.add(org);
  307. }
  308. JSONObject org=new JSONObject();
  309. org.put("records",arr);
  310. org.put("total",result.getTotal());
  311. org.put("current",result.getCurrent());
  312. return success(org);
  313. }
  314. }