LiveTask.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. package com.fs.task;
  2. import com.fs.common.annotation.QuartzRunnable;
  3. import com.fs.common.core.redis.RedisCache;
  4. import com.fs.erp.domain.ErpDeliverys;
  5. import com.fs.erp.domain.ErpOrderQuery;
  6. import com.fs.erp.dto.ErpOrderQueryRequert;
  7. import com.fs.erp.dto.ErpOrderQueryResponse;
  8. import com.fs.erp.service.FsJstAftersalePushService;
  9. import com.fs.erp.service.impl.JSTErpOrderServiceImpl;
  10. import com.fs.erp.utils.JstApiExceptionUtils;
  11. import com.fs.erp.service.jst.JstLiveDeliverySyncService;
  12. import com.fs.express.FsStoreDeliversService;
  13. import com.fs.common.utils.StringUtils;
  14. import com.fs.huifuPay.domain.HuiFuQueryOrderResult;
  15. import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayQueryRequest;
  16. import com.fs.live.domain.LiveOrderPayment;
  17. import com.fs.live.mapper.LiveOrderPaymentMapper;
  18. import com.fs.live.vo.LiveOrderPaymentVo;
  19. import com.fs.pay.pay.domain.OrderResult;
  20. import com.fs.pay.pay.dto.OrderQueryDTO;
  21. import com.fs.pay.pay.service.PayService;
  22. import com.fs.huifuPay.service.HuiFuService;
  23. import com.fs.live.utils.redis.RedisBatchHandler;
  24. import com.fs.live.domain.LiveAfterSales;
  25. import com.fs.live.domain.LiveOrder;
  26. import com.fs.live.service.*;
  27. import com.fs.store.domain.FsExpress;
  28. import com.fs.store.enums.OrderLogEnum;
  29. import com.fs.store.param.LiveAfterSalesAudit1Param;
  30. import com.fs.store.service.IFsExpressService;
  31. import com.fs.store.service.IFsUserService;
  32. import com.google.common.collect.Lists;
  33. import org.apache.commons.collections4.CollectionUtils;
  34. import org.slf4j.Logger;
  35. import org.slf4j.LoggerFactory;
  36. import org.springframework.beans.factory.annotation.Autowired;
  37. import org.springframework.beans.factory.annotation.Value;
  38. import org.springframework.scheduling.annotation.Scheduled;
  39. import org.springframework.stereotype.Component;
  40. import java.text.ParseException;
  41. import java.text.SimpleDateFormat;
  42. import java.util.ArrayList;
  43. import java.util.List;
  44. import java.util.concurrent.TimeUnit;
  45. import static com.fs.live.utils.redis.RedisBatchHandler.CONSUME_INTERVAL;
  46. /**
  47. * 定时任务调度
  48. * @author fs
  49. */
  50. @Component("liveTask")
  51. public class LiveTask {
  52. Logger logger = LoggerFactory.getLogger(LiveTask.class);
  53. @Autowired
  54. private ILiveOrderService liveOrderService;
  55. @Autowired
  56. private LiveOrderPaymentMapper liveOrderPaymentMapper;
  57. @Autowired
  58. private HuiFuService huiFuService;
  59. @Autowired
  60. private PayService ybPayService;
  61. @Autowired
  62. private ILiveAfterSalesService afterSalesService;
  63. @Autowired
  64. private JSTErpOrderServiceImpl jstErpOrderService;
  65. @Autowired
  66. private IFsExpressService expressService;
  67. @Autowired
  68. private ILiveOrderLogsService orderLogsService;
  69. @Autowired
  70. public FsJstAftersalePushService fsJstAftersalePushService;
  71. @Autowired
  72. public RedisBatchHandler redisBatchHandler;
  73. @Autowired
  74. private IFsUserService fsUserService;
  75. @Autowired
  76. private RedisCache redisCache;
  77. private static final String APP_USER_SYNC_TASK_LOCK_KEY = "task:live:app_user_sync:lock";
  78. private static final long APP_USER_SYNC_TASK_LOCK_SECONDS = 600L;
  79. /** 两个 APP 用户同步任务错峰启动间隔(秒) */
  80. private static final long APP_USER_SYNC_TASK_STAGGER_SECONDS = 15L;
  81. private static final int DELIVERY_QUERY_BATCH_SIZE = 30;
  82. // 订单银行回调数据丢失补偿
  83. public void recoveryBankOrder() {
  84. // 查询出来最近15分钟的订单 待支付 未退款
  85. List<LiveOrder> list = liveOrderService.selectBankOrder();
  86. if (CollectionUtils.isEmpty(list)) {
  87. return;
  88. }
  89. for (LiveOrder order : list) {
  90. try {
  91. LiveOrderPaymentVo payment = liveOrderPaymentMapper.selectLiveOrderPaymentByPaymentIdNew(order.getOrderId());
  92. if (payment == null || payment.getStatus() == null || payment.getStatus() != 0) {
  93. continue;
  94. }
  95. if (StringUtils.isEmpty(payment.getTradeNo()) || StringUtils.isEmpty(payment.getPayMode())) {
  96. continue;
  97. }
  98. String payMode = payment.getPayMode();
  99. if ("hf".equals(payMode)) {
  100. V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
  101. request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
  102. request.setOrgHfSeqId(payment.getTradeNo());
  103. HuiFuQueryOrderResult o = huiFuService.queryOrder(request);
  104. logger.info("直播订单补偿 汇付查询 orderId={} resp={}", order.getOrderId(), o);
  105. if (o != null && "00000000".equals(o.getResp_code()) && "S".equals(o.getTrans_stat())) {
  106. String[] parts = o.getOrg_req_seq_id().split("-");
  107. if (parts.length >= 2 && "live".equals(parts[0])) {
  108. liveOrderService.payConfirm(1, null, parts[1], o.getOrg_hf_seq_id(), o.getOut_trans_id(), o.getParty_order_id());
  109. }
  110. }
  111. } else if ("yb".equals(payMode)) {
  112. OrderQueryDTO q = new OrderQueryDTO();
  113. q.setUpOrderId(payment.getTradeNo());
  114. OrderResult orderResult = ybPayService.getOrder(q);
  115. if (orderResult == null) {
  116. continue;
  117. }
  118. if ("4".equals(orderResult.getState()) || "5".equals(orderResult.getState())) {
  119. continue;
  120. }
  121. if (!"0".equals(orderResult.getState()) || !"100".equals(orderResult.getStatus())) {
  122. continue;
  123. }
  124. String[] parts = orderResult.getLowOrderId().split("-");
  125. if (parts.length >= 2 && "live".equals(parts[0])) {
  126. liveOrderService.payConfirm(1, null, parts[1], payment.getTradeNo(), orderResult.getBankTrxId(), orderResult.getBankOrderId());
  127. }
  128. } else if ("tzbk".equals(payMode)) {
  129. logger.debug("直播订单补偿跳过台州银行支付 orderId={}", order.getOrderId());
  130. }
  131. } catch (Exception e) {
  132. logger.error("直播订单银行补偿失败 orderId={}", order.getOrderId(), e);
  133. }
  134. }
  135. }
  136. /**
  137. * 超时订单自动取消
  138. */
  139. @QuartzRunnable(name = "超时订单自动取消")
  140. public void orderCancel(){
  141. liveOrderService.orderCancel();
  142. }
  143. /**
  144. * 发货任务
  145. */
  146. @QuartzRunnable(name = "发货任务")
  147. public void deliveryOp() throws InterruptedException {
  148. List<LiveOrder> list = liveOrderService.selectDeliverPenddingData();
  149. ArrayList<Long> oIds = new ArrayList<>();
  150. for (LiveOrder liveOrder : list) {
  151. if (StringUtils.isNotEmpty(liveOrder.getExtendOrderId())) {
  152. oIds.add(Long.parseLong(liveOrder.getExtendOrderId()));
  153. }
  154. }
  155. if (!CollectionUtils.isEmpty(oIds)) {
  156. jstErpOrderDelivery(oIds);
  157. }
  158. }
  159. @Value("${jst.shop_code}")
  160. private String JST_SHOP_ID;
  161. private void jstErpOrderDelivery(List<Long> oIds) throws InterruptedException {
  162. if (CollectionUtils.isEmpty(oIds)) {
  163. return;
  164. }
  165. List<List<Long>> batches = Lists.partition(oIds, DELIVERY_QUERY_BATCH_SIZE);
  166. for (List<Long> batch : batches) {
  167. List<String> extendIds = new ArrayList<>();
  168. for (Long oId : batch) {
  169. extendIds.add(oId.toString());
  170. }
  171. int pageIndex = 1;
  172. boolean hasNext;
  173. do {
  174. Thread.sleep(300);
  175. ErpOrderQueryRequert request = new ErpOrderQueryRequert();
  176. request.setPage_size(DELIVERY_QUERY_BATCH_SIZE);
  177. request.setPage_index(pageIndex);
  178. request.setShop_id(JST_SHOP_ID);
  179. request.setO_ids(batch);
  180. ErpOrderQueryResponse response = jstErpOrderService.getOrderLive(request);
  181. hasNext = response.hasNextSafe();
  182. liveOrderService.updateUpdateTimeByExtendIds(extendIds);
  183. if (response.getOrders() != null) {
  184. for (ErpOrderQuery orderQuery : response.getOrders()) {
  185. if (orderQuery.getDeliverys() == null || orderQuery.getDeliverys().isEmpty()) {
  186. continue;
  187. }
  188. for (ErpDeliverys delivery : orderQuery.getDeliverys()) {
  189. if (!delivery.getDelivery() || org.apache.commons.lang3.StringUtils.isEmpty(delivery.getMail_no())) {
  190. continue;
  191. }
  192. LiveOrder liveOrder = liveOrderService.selectLiveOrderByOrderCode(orderQuery.getCode());
  193. if (liveOrder == null) {
  194. logger.warn("直播发货任务未找到订单 orderCode={}", orderQuery.getCode());
  195. continue;
  196. }
  197. orderLogsService.create(liveOrder.getOrderId(), OrderLogEnum.DELIVERY_GOODS.getValue(),
  198. OrderLogEnum.DELIVERY_GOODS.getDesc());
  199. try {
  200. for (ErpDeliverys deli : orderQuery.getDeliverys()) {
  201. FsExpress express = expressService.selectFsExpressByOmsCode(deli.getExpress_code());
  202. if (express == null) {
  203. logger.error("当前express_code: {} 不存在!", deli.getExpress_code());
  204. continue;
  205. }
  206. if (deli.getDelivery()) {
  207. liveOrderService.deliveryOrder(orderQuery.getCode(), deli.getMail_no(),
  208. deli.getExpress_code(), deli.getExpress_name());
  209. }
  210. }
  211. logger.info("直播订单 {} 发货信息同步成功", orderQuery.getCode());
  212. } catch (Exception e) {
  213. logger.error("同步直播订单发货状态失败 orderCode={} mailNo={}",
  214. orderQuery.getCode(), delivery.getMail_no(), e);
  215. }
  216. }
  217. }
  218. }
  219. pageIndex++;
  220. } while (hasNext);
  221. }
  222. }
  223. /**
  224. * 同步近三天直播订单关联的APP用户数据
  225. */
  226. @QuartzRunnable(name = "同步APP用户数据")
  227. public void syncAppUser() {
  228. if (!tryAcquireAppUserSyncLock()) {
  229. logger.debug("同步APP用户数据任务跳过,其他任务正在执行");
  230. return;
  231. }
  232. try {
  233. fsUserService.syncAppUsersForRecentLiveOrders(3);
  234. } catch (Exception e) {
  235. logger.error("同步APP用户数据失败", e);
  236. } finally {
  237. releaseAppUserSyncLock();
  238. }
  239. }
  240. /**
  241. * 从 Redis 拉取下单时缓存的待同步 APP 用户并同步
  242. */
  243. @QuartzRunnable(name = "同步APP用户数据(Redis)")
  244. public void syncAppUserFromRedis() {
  245. try {
  246. Thread.sleep(APP_USER_SYNC_TASK_STAGGER_SECONDS * 1000);
  247. } catch (InterruptedException e) {
  248. Thread.currentThread().interrupt();
  249. return;
  250. }
  251. if (!tryAcquireAppUserSyncLock()) {
  252. logger.debug("Redis同步APP用户数据任务跳过,其他任务正在执行");
  253. return;
  254. }
  255. try {
  256. fsUserService.syncPendingAppUsersFromRedis();
  257. } catch (Exception e) {
  258. logger.error("Redis同步APP用户数据失败", e);
  259. } finally {
  260. releaseAppUserSyncLock();
  261. }
  262. }
  263. private boolean tryAcquireAppUserSyncLock() {
  264. return redisCache.setIfAbsent(APP_USER_SYNC_TASK_LOCK_KEY, "1", APP_USER_SYNC_TASK_LOCK_SECONDS, TimeUnit.SECONDS);
  265. }
  266. private void releaseAppUserSyncLock() {
  267. redisCache.deleteObject(APP_USER_SYNC_TASK_LOCK_KEY);
  268. }
  269. /**
  270. * 退款自动处理 24小时未审核自动审核通过 每小时执行一次
  271. */
  272. @QuartzRunnable(name = "直播售后自动审核")
  273. public void refundOp() {
  274. //获取所有退款申请
  275. List<LiveAfterSales> list = afterSalesService.selectLiveAfterSalesByDoAudit();
  276. if (list != null) {
  277. for (LiveAfterSales afterSales : list) {
  278. //仅退款
  279. // if (afterSales.getServiceType().equals(0)) {
  280. LiveAfterSalesAudit1Param audit1Param = new LiveAfterSalesAudit1Param();
  281. audit1Param.setSalesId(afterSales.getId());
  282. audit1Param.setOperator("平台");
  283. afterSalesService.audit1(audit1Param);
  284. // }
  285. }
  286. }
  287. }
  288. /**
  289. * 批量推管易
  290. * @throws ParseException 解析异常
  291. */
  292. @QuartzRunnable(name = "批量推管易")
  293. public void updateOrderItem() throws ParseException {
  294. List<Long> ids = liveOrderService.selectOrderIdByNoErp();
  295. for (Long id : ids) {
  296. try {
  297. liveOrderService.createOmsOrder(id);
  298. } catch (Exception e) {
  299. logger.error("推送管易失败 {}", id, e);
  300. if (JstApiExceptionUtils.isRateLimitExceeded(e)) {
  301. logger.warn("聚水潭调用推送频次超限,终止本批次推单");
  302. break;
  303. }
  304. if (JstApiExceptionUtils.isErrorToken(e)) {
  305. logger.warn("聚水潭调用推送无效token,终止本批次推单");
  306. break;
  307. }
  308. }
  309. }
  310. }
  311. @Autowired
  312. FsStoreDeliversService fsStoreDeliverService;
  313. /**
  314. * 同步物流状态
  315. */
  316. @QuartzRunnable(name = "直播同步物流状态")
  317. public void syncExpress() {
  318. List<Long> ids = liveOrderService.selectSyncExpressIds();
  319. for (Long id : ids) {
  320. liveOrderService.syncExpress(id);
  321. fsStoreDeliverService.finishOrder(id,1);
  322. }
  323. }
  324. /**
  325. * 更新发货状态
  326. */
  327. @QuartzRunnable(name = "直播发货任务")
  328. public void updateExpress() {
  329. List<LiveOrder> list = liveOrderService.selectUpdateExpress();
  330. for (LiveOrder order : list) {
  331. try{
  332. liveOrderService.syncDeliveryOrder(order);
  333. }catch (Exception e) {
  334. logger.error("获取订单是否发货失败!原因: ",e);
  335. }
  336. }
  337. }
  338. /**
  339. * 更新流量
  340. */
  341. @Scheduled(fixedRate = CONSUME_INTERVAL)
  342. public void insertLiveTrralog() {
  343. redisBatchHandler.consumeBatchData();
  344. }
  345. }