فهرست منبع

直播和商城的银行补偿机制

yuhongqi 1 ماه پیش
والد
کامیت
72d6b8e394

+ 75 - 0
fs-admin/src/main/java/com/fs/task/LiveTask.java

@@ -9,6 +9,16 @@ import com.fs.erp.service.FsJstAftersalePushService;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.erp.utils.ErpContextHolder;
 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;
@@ -27,6 +37,7 @@ import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.List;
 
 import static com.fs.live.utils.redis.RedisBatchHandler.CONSUME_INTERVAL;
@@ -42,6 +53,12 @@ public class LiveTask {
 
     @Autowired
     private ILiveOrderService liveOrderService;
+    @Autowired
+    private LiveOrderPaymentMapper liveOrderPaymentMapper;
+    @Autowired
+    private HuiFuService huiFuService;
+    @Autowired
+    private PayService ybPayService;
 
     @Autowired
     private ILiveAfterSalesService afterSalesService;
@@ -67,6 +84,64 @@ public class LiveTask {
     @Autowired
     public RedisBatchHandler redisBatchHandler;
 
+    // 订单银行回调数据丢失补偿
+    public void recoveryBankOrder() {
+        // 查询出来最近15分钟的订单 待支付 未退款
+        List<LiveOrder> 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);
+            }
+        }
+    }
+
     /**
      * 超时订单自动取消
      */

+ 104 - 2
fs-admin/src/main/java/com/fs/task/StoreTask.java

@@ -4,6 +4,18 @@ import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONUtil;
 import com.fs.common.annotation.QuartzRunnable;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.StringUtils;
+import com.fs.huifuPay.domain.HuiFuQueryOrderResult;
+import com.fs.huifuPay.dto.*;
+import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayQueryRequest;
+import com.fs.huifuPay.service.HuiFuService;
+import com.fs.live.service.ILiveOrderService;
+import com.fs.pay.pay.domain.OrderResult;
+import com.fs.pay.pay.dto.OrderQueryDTO;
+import com.fs.pay.pay.service.PayService;
+import com.fs.store.domain.TzConfigInfoDTO;
+import com.fs.tzBank.TzBankService;
+import com.fs.tzBank.utils.TzConfigUtils;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.core.security.SecurityUtils;
@@ -31,7 +43,7 @@ import com.fs.wx.mapper.FsWxExpressTaskMapper;
 import com.google.common.util.concurrent.RateLimiter;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang.ObjectUtils;
-import org.apache.commons.lang3.StringUtils;
+import org.apache.http.util.Asserts;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -41,6 +53,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
@@ -116,7 +129,14 @@ public class StoreTask {
 
     @Autowired
     private IFsStorePaymentService fsStorePaymentService;
-
+    @Autowired
+    private HuiFuService huiFuService;
+    @Autowired
+    private PayService ybPayService;
+    @Autowired
+    private TzBankService tzBankService;
+    @Autowired
+    private ILiveOrderService liveOrderService;
 
     @Autowired
     private FsWxExpressTaskMapper fsWxExpressTaskMapper;
@@ -130,6 +150,88 @@ public class StoreTask {
     @Autowired
     private FsJstCodPushService fsJstCodPushService;
 
+
+    // 订单银行回调数据丢失补偿(与 FsStorePaymentController.returnPayStatus 一致,仅处理商城近期待支付订单下的支付单)
+    public void recoveryBankOrder() {
+        List<FsStoreOrder> list = fsStoreOrderService.selectBankOrder();
+        if (CollectionUtils.isEmpty(list)) {
+            return;
+        }
+        for (FsStoreOrder storeOrder : list) {
+            try {
+                List<FsStorePayment> payments = fsStorePaymentService.selectFsStorePaymentByOrderIdNew(storeOrder.getId());
+                if (CollectionUtils.isEmpty(payments)) {
+                    continue;
+                }
+                for (FsStorePayment payment : payments) {
+                    if (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={}", storeOrder.getId(), 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) {
+                                continue;
+                            }
+                            if (parts[0].equals("store")) {
+                                orderService.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) {
+                            continue;
+                        }
+                        if (parts[0].equals("store")) {
+                            orderService.payConfirm(1, null, parts[1], payment.getTradeNo(), orderResult.getBankTrxId(), orderResult.getBankOrderId());
+                        }
+                    } else if ("tzbk".equals(payMode)) {
+                        FsStoreOrder fsOrder = orderService.selectFsStoreOrderById(payment.getOrderId());
+                        Asserts.notNull(fsOrder, "当前订单不存在!");
+                        RequestDTO<QueryOrderRestDTO> requestDTO = new RequestDTO<>();
+                        QueryOrderRestDTO queryOrderRestDTO = new QueryOrderRestDTO();
+                        queryOrderRestDTO.setOrderFlowNo(payment.getTradeNo());
+                        TzConfigInfoDTO tzConfigInfoDTO = TzConfigUtils.getConfig();
+                        queryOrderRestDTO.setPlatMerCstNo(tzConfigInfoDTO.getPlatMerCstNo());
+                        requestDTO.setReqBody(queryOrderRestDTO);
+                        requestDTO.setReqHeader(TzReqHeaderDTO.getInstance(payment.getPayCode()));
+                        TzReqResultDTO<QueryOrderInfoDTO> resultDTO = tzBankService.payQueryOrder(requestDTO);
+                        if (resultDTO == null || !"00000000".equals(resultDTO.getRetCode())) {
+                            logger.info("商城订单补偿 台州银行查询失败 orderId={} ret={}", storeOrder.getId(), resultDTO);
+                            continue;
+                        }
+                        QueryOrderInfoDTO body = resultDTO.getBody();
+                        orderService.payConfirm(1, fsOrder.getId(), payment.getPayCode(),
+                                payment.getTradeNo(), body.getChlTrxId(), payment.getTradeNo());
+                    }
+                }
+            } catch (Exception e) {
+                logger.error("商城订单银行补偿失败 orderId={}", storeOrder.getId(), e);
+            }
+        }
+    }
+
     /**
      * 推送jst售后单
      */

+ 6 - 0
fs-service-system/src/main/java/com/fs/live/mapper/LiveOrderMapper.java

@@ -140,4 +140,10 @@ public interface LiveOrderMapper {
     List<LiveOrder> selectOrderByLiveId(@Param("liveId") Long liveId);
 
     int insertLiveOrderTest(LiveOrder liveOrder);
+
+    /*
+     * 查询订单创建时间为最近30分钟的订单
+     * */
+    @Select("SELECT * FROM live_order WHERE create_time >= DATE_SUB(NOW(), INTERVAL 25 MINUTE) AND create_time <= DATE_SUB(NOW(), INTERVAL 4 MINUTE) AND status = 1 AND (refund_status IS NULL OR refund_status = '' OR refund_status = '0')")
+    List<LiveOrder> selectBankOrder();
 }

+ 2 - 0
fs-service-system/src/main/java/com/fs/live/service/ILiveOrderService.java

@@ -224,4 +224,6 @@ public interface ILiveOrderService {
     void initStock();
 
     R createLiveOrderTest(LiveOrder param);
+
+    List<LiveOrder> selectBankOrder();
 }

+ 20 - 0
fs-service-system/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -541,6 +541,21 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
     @Override
     @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRED)
     public String payConfirm(Integer type, Long orderId, String payCode, String tradeNo, String bankTransactionId, String bankSerialNo) {
+        String lockKey = (type != null && type.equals(1) && org.apache.commons.lang3.StringUtils.isNotEmpty(payCode))
+                ? "pay_confirm:live:pc:" + payCode
+                : "pay_confirm:live:oid:" + orderId;
+        if (!redisCache.setIfAbsent(lockKey, "1", 2, TimeUnit.MINUTES)) {
+            log.warn("直播订单 payConfirm 未获取到分布式锁,跳过: {}", lockKey);
+            return "";
+        }
+        try {
+            return doPayConfirmLocked(type, orderId, payCode, tradeNo, bankTransactionId, bankSerialNo);
+        } finally {
+            redisCache.deleteObject(lockKey);
+        }
+    }
+
+    private String doPayConfirmLocked(Integer type, Long orderId, String payCode, String tradeNo, String bankTransactionId, String bankSerialNo) {
         Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
         try {
             LiveOrder order = null;
@@ -3095,6 +3110,11 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         }
     }
 
+    @Override
+    public List<LiveOrder> selectBankOrder() {
+        return baseMapper.selectBankOrder();
+    }
+
     @Autowired
     ILiveService liveService;
 

+ 4 - 0
fs-service-system/src/main/java/com/fs/store/mapper/FsStoreOrderMapper.java

@@ -10,6 +10,7 @@ import com.fs.company.param.CompanyStatisticsParam;
 import com.fs.company.vo.CompanySmsLogsStatisticsVO;
 import com.fs.company.vo.CompanyTuiMoneyStatisticsVO;
 import com.fs.company.vo.StoreOrderStatisticsVO;
+import com.fs.live.domain.LiveOrder;
 import com.fs.store.domain.FsStoreOrder;
 import com.fs.store.domain.FsStoreOrderItem;
 import com.fs.store.param.*;
@@ -1010,4 +1011,7 @@ public interface FsStoreOrderMapper
     List<FsStoreOrder> selectDeliverPendingData();
 
     List<FsStoreOrder> selectFsOutDateOrder();
+
+    @Select("SELECT * FROM fs_store_order WHERE create_time >= DATE_SUB(NOW(), INTERVAL 25 MINUTE) AND create_time <= DATE_SUB(NOW(), INTERVAL 4 MINUTE) AND status = 0")
+    List<FsStoreOrder> selectBankOrder();
 }

+ 3 - 0
fs-service-system/src/main/java/com/fs/store/service/IFsStoreOrderService.java

@@ -10,6 +10,7 @@ import com.fs.api.param.OrderListParam;
 import com.fs.api.vo.OrderListVO;
 import com.fs.common.core.domain.R;
 import com.fs.company.domain.CompanyUser;
+import com.fs.live.domain.LiveOrder;
 import com.fs.store.domain.FsStoreOrder;
 import com.fs.store.dto.ExpressNotifyDTO;
 import com.fs.store.dto.ExpressResultDTO;
@@ -305,4 +306,6 @@ public interface IFsStoreOrderService
     void cancelPay(FsStoreOrderPayParam param);
 
     R getInfo2(Long id, Integer type);
+
+    List<FsStoreOrder> selectBankOrder();
 }

+ 21 - 2
fs-service-system/src/main/java/com/fs/store/service/impl/FsStoreOrderServiceImpl.java

@@ -1980,10 +1980,30 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
 
     }
 
+    @Override
+    public List<FsStoreOrder> selectBankOrder() {
+        return fsStoreOrderMapper.selectBankOrder();
+    }
+
     @Override
     @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED)
     //类型1支付回调 类型2货到付款
-    public synchronized String  payConfirm(Integer type,Long orderId,String payCode,String tradeNo,String bankTransactionId,String bankSerialNo) {
+    public String payConfirm(Integer type,Long orderId,String payCode,String tradeNo,String bankTransactionId,String bankSerialNo) {
+        String lockKey = (type != null && type.equals(1) && org.apache.commons.lang3.StringUtils.isNotEmpty(payCode))
+                ? "pay_confirm:store:pc:" + payCode
+                : "pay_confirm:store:oid:" + orderId;
+        if (!redisCache.setIfAbsent(lockKey, "1", 2, TimeUnit.MINUTES)) {
+            logger.warn("商城订单 payConfirm 未获取到分布式锁,跳过: {}", lockKey);
+            return "";
+        }
+        try {
+            return doStorePayConfirmLocked(type, orderId, payCode, tradeNo, bankTransactionId, bankSerialNo);
+        } finally {
+            redisCache.deleteObject(lockKey);
+        }
+    }
+
+    private String doStorePayConfirmLocked(Integer type,Long orderId,String payCode,String tradeNo,String bankTransactionId,String bankSerialNo) {
         //支付订单
         try {
             FsStoreOrder order=null;
@@ -2071,7 +2091,6 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
         return "SUCCESS";
     }
 
-
     public  boolean containsAddress(String companyName) {
         String[] items= {"新疆","西藏","内蒙古","海南"};
         boolean found = false;