package com.fs.task; import com.fs.common.annotation.QuartzRunnable; import com.fs.common.core.redis.RedisCache; import com.fs.erp.domain.ErpDeliverys; import com.fs.erp.domain.ErpOrderQuery; import com.fs.erp.dto.ErpOrderQueryRequert; import com.fs.erp.dto.ErpOrderQueryResponse; import com.fs.erp.service.FsJstAftersalePushService; import com.fs.erp.service.impl.JSTErpOrderServiceImpl; import com.fs.erp.utils.JstApiExceptionUtils; import com.fs.erp.service.jst.JstLiveDeliverySyncService; import com.fs.express.FsStoreDeliversService; import com.fs.common.utils.StringUtils; import com.fs.huifuPay.domain.HuiFuQueryOrderResult; import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayQueryRequest; import com.fs.live.domain.LiveOrderPayment; import com.fs.live.mapper.LiveOrderPaymentMapper; import com.fs.live.vo.LiveOrderPaymentVo; import com.fs.pay.pay.domain.OrderResult; import com.fs.pay.pay.dto.OrderQueryDTO; import com.fs.pay.pay.service.PayService; import com.fs.huifuPay.service.HuiFuService; import com.fs.live.utils.redis.RedisBatchHandler; import com.fs.live.domain.LiveAfterSales; import com.fs.live.domain.LiveOrder; import com.fs.live.service.*; import com.fs.store.domain.FsExpress; import com.fs.store.enums.OrderLogEnum; import com.fs.store.param.LiveAfterSalesAudit1Param; import com.fs.store.service.IFsExpressService; import com.fs.store.service.IFsUserService; import com.google.common.collect.Lists; import org.apache.commons.collections4.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import static com.fs.live.utils.redis.RedisBatchHandler.CONSUME_INTERVAL; /** * 定时任务调度 * @author fs */ @Component("liveTask") public class LiveTask { Logger logger = LoggerFactory.getLogger(LiveTask.class); @Autowired private ILiveOrderService liveOrderService; @Autowired private LiveOrderPaymentMapper liveOrderPaymentMapper; @Autowired private HuiFuService huiFuService; @Autowired private PayService ybPayService; @Autowired private ILiveAfterSalesService afterSalesService; @Autowired private JSTErpOrderServiceImpl jstErpOrderService; @Autowired private IFsExpressService expressService; @Autowired private ILiveOrderLogsService orderLogsService; @Autowired public FsJstAftersalePushService fsJstAftersalePushService; @Autowired public RedisBatchHandler redisBatchHandler; @Autowired private IFsUserService fsUserService; @Autowired private RedisCache redisCache; private static final String APP_USER_SYNC_TASK_LOCK_KEY = "task:live:app_user_sync:lock"; private static final long APP_USER_SYNC_TASK_LOCK_SECONDS = 600L; /** 两个 APP 用户同步任务错峰启动间隔(秒) */ private static final long APP_USER_SYNC_TASK_STAGGER_SECONDS = 15L; private static final int DELIVERY_QUERY_BATCH_SIZE = 30; // 订单银行回调数据丢失补偿 public void recoveryBankOrder() { // 查询出来最近15分钟的订单 待支付 未退款 List list = liveOrderService.selectBankOrder(); if (CollectionUtils.isEmpty(list)) { return; } for (LiveOrder order : list) { try { LiveOrderPaymentVo payment = liveOrderPaymentMapper.selectLiveOrderPaymentByPaymentIdNew(order.getOrderId()); if (payment == null || payment.getStatus() == null || payment.getStatus() != 0) { continue; } if (StringUtils.isEmpty(payment.getTradeNo()) || StringUtils.isEmpty(payment.getPayMode())) { continue; } String payMode = payment.getPayMode(); if ("hf".equals(payMode)) { V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest(); request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime())); request.setOrgHfSeqId(payment.getTradeNo()); HuiFuQueryOrderResult o = huiFuService.queryOrder(request); logger.info("直播订单补偿 汇付查询 orderId={} resp={}", order.getOrderId(), o); if (o != null && "00000000".equals(o.getResp_code()) && "S".equals(o.getTrans_stat())) { String[] parts = o.getOrg_req_seq_id().split("-"); if (parts.length >= 2 && "live".equals(parts[0])) { liveOrderService.payConfirm(1, null, parts[1], o.getOrg_hf_seq_id(), o.getOut_trans_id(), o.getParty_order_id()); } } } else if ("yb".equals(payMode)) { OrderQueryDTO q = new OrderQueryDTO(); q.setUpOrderId(payment.getTradeNo()); OrderResult orderResult = ybPayService.getOrder(q); if (orderResult == null) { continue; } if ("4".equals(orderResult.getState()) || "5".equals(orderResult.getState())) { continue; } if (!"0".equals(orderResult.getState()) || !"100".equals(orderResult.getStatus())) { continue; } String[] parts = orderResult.getLowOrderId().split("-"); if (parts.length >= 2 && "live".equals(parts[0])) { liveOrderService.payConfirm(1, null, parts[1], payment.getTradeNo(), orderResult.getBankTrxId(), orderResult.getBankOrderId()); } } else if ("tzbk".equals(payMode)) { logger.debug("直播订单补偿跳过台州银行支付 orderId={}", order.getOrderId()); } } catch (Exception e) { logger.error("直播订单银行补偿失败 orderId={}", order.getOrderId(), e); } } } /** * 超时订单自动取消 */ @QuartzRunnable(name = "超时订单自动取消") public void orderCancel(){ liveOrderService.orderCancel(); } /** * 发货任务 */ @QuartzRunnable(name = "发货任务") public void deliveryOp() throws InterruptedException { List list = liveOrderService.selectDeliverPenddingData(); ArrayList oIds = new ArrayList<>(); for (LiveOrder liveOrder : list) { if (StringUtils.isNotEmpty(liveOrder.getExtendOrderId())) { oIds.add(Long.parseLong(liveOrder.getExtendOrderId())); } } if (!CollectionUtils.isEmpty(oIds)) { jstErpOrderDelivery(oIds); } } @Value("${jst.shop_code}") private String JST_SHOP_ID; private void jstErpOrderDelivery(List oIds) throws InterruptedException { if (CollectionUtils.isEmpty(oIds)) { return; } List> batches = Lists.partition(oIds, DELIVERY_QUERY_BATCH_SIZE); for (List batch : batches) { List extendIds = new ArrayList<>(); for (Long oId : batch) { extendIds.add(oId.toString()); } int pageIndex = 1; boolean hasNext; do { Thread.sleep(300); ErpOrderQueryRequert request = new ErpOrderQueryRequert(); request.setPage_size(DELIVERY_QUERY_BATCH_SIZE); request.setPage_index(pageIndex); request.setShop_id(JST_SHOP_ID); request.setO_ids(batch); ErpOrderQueryResponse response = jstErpOrderService.getOrderLive(request); hasNext = response.hasNextSafe(); liveOrderService.updateUpdateTimeByExtendIds(extendIds); if (response.getOrders() != null) { for (ErpOrderQuery orderQuery : response.getOrders()) { if (orderQuery.getDeliverys() == null || orderQuery.getDeliverys().isEmpty()) { continue; } for (ErpDeliverys delivery : orderQuery.getDeliverys()) { if (!delivery.getDelivery() || org.apache.commons.lang3.StringUtils.isEmpty(delivery.getMail_no())) { continue; } LiveOrder liveOrder = liveOrderService.selectLiveOrderByOrderCode(orderQuery.getCode()); if (liveOrder == null) { logger.warn("直播发货任务未找到订单 orderCode={}", orderQuery.getCode()); continue; } orderLogsService.create(liveOrder.getOrderId(), OrderLogEnum.DELIVERY_GOODS.getValue(), OrderLogEnum.DELIVERY_GOODS.getDesc()); try { for (ErpDeliverys deli : orderQuery.getDeliverys()) { FsExpress express = expressService.selectFsExpressByOmsCode(deli.getExpress_code()); if (express == null) { logger.error("当前express_code: {} 不存在!", deli.getExpress_code()); continue; } if (deli.getDelivery()) { liveOrderService.deliveryOrder(orderQuery.getCode(), deli.getMail_no(), deli.getExpress_code(), deli.getExpress_name()); } } logger.info("直播订单 {} 发货信息同步成功", orderQuery.getCode()); } catch (Exception e) { logger.error("同步直播订单发货状态失败 orderCode={} mailNo={}", orderQuery.getCode(), delivery.getMail_no(), e); } } } } pageIndex++; } while (hasNext); } } /** * 同步近三天直播订单关联的APP用户数据 */ @QuartzRunnable(name = "同步APP用户数据") public void syncAppUser() { if (!tryAcquireAppUserSyncLock()) { logger.debug("同步APP用户数据任务跳过,其他任务正在执行"); return; } try { fsUserService.syncAppUsersForRecentLiveOrders(3); } catch (Exception e) { logger.error("同步APP用户数据失败", e); } finally { releaseAppUserSyncLock(); } } /** * 从 Redis 拉取下单时缓存的待同步 APP 用户并同步 */ @QuartzRunnable(name = "同步APP用户数据(Redis)") public void syncAppUserFromRedis() { try { Thread.sleep(APP_USER_SYNC_TASK_STAGGER_SECONDS * 1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } if (!tryAcquireAppUserSyncLock()) { logger.debug("Redis同步APP用户数据任务跳过,其他任务正在执行"); return; } try { fsUserService.syncPendingAppUsersFromRedis(); } catch (Exception e) { logger.error("Redis同步APP用户数据失败", e); } finally { releaseAppUserSyncLock(); } } private boolean tryAcquireAppUserSyncLock() { return redisCache.setIfAbsent(APP_USER_SYNC_TASK_LOCK_KEY, "1", APP_USER_SYNC_TASK_LOCK_SECONDS, TimeUnit.SECONDS); } private void releaseAppUserSyncLock() { redisCache.deleteObject(APP_USER_SYNC_TASK_LOCK_KEY); } /** * 退款自动处理 24小时未审核自动审核通过 每小时执行一次 */ @QuartzRunnable(name = "直播售后自动审核") public void refundOp() { //获取所有退款申请 List list = afterSalesService.selectLiveAfterSalesByDoAudit(); if (list != null) { for (LiveAfterSales afterSales : list) { //仅退款 // if (afterSales.getServiceType().equals(0)) { LiveAfterSalesAudit1Param audit1Param = new LiveAfterSalesAudit1Param(); audit1Param.setSalesId(afterSales.getId()); audit1Param.setOperator("平台"); afterSalesService.audit1(audit1Param); // } } } } /** * 批量推管易 * @throws ParseException 解析异常 */ @QuartzRunnable(name = "批量推管易") public void updateOrderItem() throws ParseException { List ids = liveOrderService.selectOrderIdByNoErp(); for (Long id : ids) { try { liveOrderService.createOmsOrder(id); } catch (Exception e) { logger.error("推送管易失败 {}", id, e); if (JstApiExceptionUtils.isRateLimitExceeded(e)) { logger.warn("聚水潭调用推送频次超限,终止本批次推单"); break; } if (JstApiExceptionUtils.isErrorToken(e)) { logger.warn("聚水潭调用推送无效token,终止本批次推单"); break; } } } } @Autowired FsStoreDeliversService fsStoreDeliverService; /** * 同步物流状态 */ @QuartzRunnable(name = "直播同步物流状态") public void syncExpress() { List ids = liveOrderService.selectSyncExpressIds(); for (Long id : ids) { liveOrderService.syncExpress(id); fsStoreDeliverService.finishOrder(id,1); } } /** * 更新发货状态 */ @QuartzRunnable(name = "直播发货任务") public void updateExpress() { List list = liveOrderService.selectUpdateExpress(); for (LiveOrder order : list) { try{ liveOrderService.syncDeliveryOrder(order); }catch (Exception e) { logger.error("获取订单是否发货失败!原因: ",e); } } } /** * 更新流量 */ @Scheduled(fixedRate = CONSUME_INTERVAL) public void insertLiveTrralog() { redisBatchHandler.consumeBatchData(); } }