package com.mzl.flower.service.payment; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.mzl.flower.config.PyamentV3Configurer; import com.mzl.flower.config.exception.ValidationException; import com.mzl.flower.config.security.SecurityUtils; import com.mzl.flower.constant.Constants; import com.mzl.flower.dto.request.payment.TransferDetailReqDTO; import com.mzl.flower.dto.request.payment.TransferReqDTO; import com.mzl.flower.dto.request.payment.UserPaymentDTO; import com.mzl.flower.entity.payment.*; import com.mzl.flower.entity.system.UserWechat; import com.mzl.flower.mapper.flower.FlowerMapper; import com.mzl.flower.mapper.payment.*; import com.mzl.flower.mapper.system.UserWechatMapper; import com.mzl.flower.service.BaseService; import com.mzl.flower.service.flower.FlowerService; import com.mzl.flower.utils.UUIDGenerator; import com.wechat.pay.java.core.notification.NotificationParser; import com.wechat.pay.java.core.notification.RequestParam; import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension; import com.wechat.pay.java.service.payments.jsapi.model.*; import com.wechat.pay.java.service.payments.jsapi.model.Amount; import com.wechat.pay.java.service.payments.model.Transaction; import com.wechat.pay.java.service.payments.model.TransactionAmount; import com.wechat.pay.java.service.refund.RefundService; import com.wechat.pay.java.service.refund.model.*; import com.wechat.pay.java.service.transferbatch.TransferBatchService; import com.wechat.pay.java.service.transferbatch.model.*; import io.micrometer.core.instrument.util.StringUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.InputStreamReader; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.wechat.pay.java.core.http.Constant; @Service @Transactional @Slf4j public class UserPaymentV3Service extends BaseService { @Autowired private UserPaymentMapper userPaymentMapper; @Autowired private RedisLockService lockService; @Autowired private UserWechatMapper wechatMapper; @Autowired private OrderMapper orderMapper; @Autowired private OrderItemMapper orderItemMapper; @Autowired private FlowerMapper flowerMapper; @Autowired private FlowerService flowerService; @Autowired private DeliveryOrderService deliveryOrderService; @Autowired private JsapiServiceExtension jsapiService; @Autowired private NotificationParser notificationParser; @Autowired private RefundService refundService; @Autowired private TransferBatchService transferBatchService; @Autowired private TransferMapper transferMapper; @Autowired private TransferDetailMapper transferDetailMapper; @Autowired private OrderRefundMapper orderRefundMapper; /** * 微信预支付 * * @param order * @return */ public Map wxPrepay(Order order){ String openId = order.getPayOpenid(); String userId = SecurityUtils.getUserId(); // UserWechat wechat = wechatMapper.selectOne(new QueryWrapper().eq("user_id", userId)); // if (wechat != null) { // openId = wechat.getOpenId(); // } if(StringUtils.isEmpty(openId)){ throw new ValidationException("openId不存在"); } UserPayment up = prepareUserPayment(userId, order); log.info("UserPayment: " + toJSONString(up)); PrepayRequest request = new PrepayRequest(); Amount amount = new Amount(); amount.setTotal(prepareAmount(up.getPaymentAmount())); request.setAmount(amount); request.setAppid(PyamentV3Configurer.customer_app_id); request.setMchid(PyamentV3Configurer.merchantId); request.setDescription(order.getOrderNo()); request.setNotifyUrl(PyamentV3Configurer.notify_url_pay); request.setOutTradeNo(up.getOrderId()); request.setTimeExpire(getTimeExpire()); Payer payer = new Payer(); payer.setOpenid(openId); request.setPayer(payer); // 调用接口 PrepayWithRequestPaymentResponse response = jsapiService.prepayWithRequestPayment(request); up.setPrepayResponse(toJSONString(response)); userPaymentMapper.insert(up); Map map = new HashMap<>(); map.put("appId", response.getAppId()); map.put("timeStamp", response.getTimeStamp()); map.put("nonceStr", response.getNonceStr()); map.put("package", response.getPackageVal()); map.put("signType", response.getSignType()); map.put("paySign", response.getPaySign()); return map; } private static String getTimeExpire(){//设置微信订单5分钟过期 // 获取当前日期和时间 ZonedDateTime zonedDateTime = ZonedDateTime.now(); // 创建一个DateTimeFormatter DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX"); // 使用formatter格式化ZonedDateTime String formattedDateTime = zonedDateTime.plusMinutes(5).format(formatter); return formattedDateTime; // 格式化日期 } private Integer prepareAmount(BigDecimal amount){ return amount.multiply(new BigDecimal(100)).intValue(); } private UserPayment prepareUserPayment(String userId, Order order){ UserPayment up = new UserPayment(); up.setId(UUIDGenerator.getUUID()); up.setUserId(userId); up.setOrderId(order.getId()); up.setPaymentAmount(order.getTotalAmount()); up.setPaymentTime(LocalDateTime.now()); up.create(userId); return up; } public ResponseEntity handlePayCallback(HttpServletRequest request) { try { ServletInputStream inputStream = request.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); // 读取请求体 StringBuilder sb = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { sb.append(line); } String notify = sb.toString(); log.info("微信支付通知: {}", notify); RequestParam requestParam = buildByHeaderRequestParam(request, notify); log.info("微信支付通知解析请求: {}", JSON.toJSONString(requestParam)); // 调用 NotificationParser.parse() 验签、解密并将 JSON 转换成具体的通知回调对象。如果验签失败,SDK 会抛出 ValidationException。 log.info("支付通知回调:验签、解密并转换成 Transaction对象:-------"); Transaction transaction = null; try { /** * 常用的通知回调调对象类型有: * 支付 Transaction * 退款 RefundNotification * 若 SDK 暂不支持的类型,请使用 Map.class,嵌套的 Json 对象将被转换成 LinkedTreeMap */ transaction = notificationParser.parse(requestParam, Transaction.class); }catch (ValidationException e) { // 签名验证失败,返回 401 UNAUTHORIZED 状态码 log.error("sign verification failed", e); return new ResponseEntity<>("", HttpStatus.UNAUTHORIZED); } log.info("Transaction:===>>>>支付CallBack状态" + transaction.getTradeState()); String originalXml = toJSONString(transaction);//回调请求内容 log.info("transaction: " + originalXml); String outTradeNo = transaction.getOutTradeNo();//对外贸易编号 String transactionId = transaction.getTransactionId();//事务处理id String orderId = outTradeNo; TransactionAmount amount = transaction.getAmount(); Integer paymentAmountCallback = amount.getTotal();//实际支付金额 单位:分 log.info("======paymentAmountCallback: " + paymentAmountCallback); Transaction.TradeStateEnum tradeState = transaction.getTradeState();//支付状态 String status = Constants.PAYMENT_STATUS.FAILED.name(); //交易状态 if (Transaction.TradeStateEnum.SUCCESS.equals(tradeState)){ status = Constants.PAYMENT_STATUS.SUCCESS.name(); } UserPaymentDTO dto = new UserPaymentDTO(); dto.setOrderId(orderId); dto.setTransactionId(transactionId); dto.setOutTradeNo(outTradeNo); dto.setOriginalXml(originalXml); dto.setPaymentAmountCallback(paymentAmountCallback + ""); dto.setStatus(status); saveCallbackInfo(dto, Constants.ORDER_STATUS_BACKEND.PAYMENT.name()); } catch (Exception e) { log.error("解析付款通知出错:{}", e.getMessage(), e); return new ResponseEntity<>("", HttpStatus.INTERNAL_SERVER_ERROR); } return new ResponseEntity<>("", HttpStatus.OK); } private Map prepareReturn(String code, String message){ Map m = new HashMap(); m.put("code", code); m.put("message", message); return m; } public RequestParam buildByHeaderRequestParam(HttpServletRequest request, String notify) { log.info("-------------------WxPay---------GetHeader--------------------BEGIN"); // HTTP 头 Wechatpay-Timestamp。签名中的时间戳。 String timestamp = request.getHeader(Constant.WECHAT_PAY_TIMESTAMP); // HTTP 头 Wechatpay-Nonce。签名中的随机数。 String nonce = request.getHeader(Constant.WECHAT_PAY_NONCE); // HTTP 头 Wechatpay-Signature-Type。签名类型。 String signType = request.getHeader("Wechatpay-Signature-Type"); //HTTP 头 Wechatpay-Serial。微信支付平台证书的序列号,验签必须使用序列号对应的微信支付平台证书。 String serialNo = request.getHeader(Constant.WECHAT_PAY_SERIAL); // HTTP 头 Wechatpay-Signature。应答的微信支付签名。 String signature = request.getHeader(Constant.WECHAT_PAY_SIGNATURE); log.info("应答的微信支付签名: {}", signature); if(StringUtils.isNotBlank(signature) && signature.contains("WECHATPAY/SIGNTEST/")){ //应对签名探测流量 //为了确保商户系统的安全,微信支付会在极少数应答或通知回调中生成错误签名,以探测商户系统是否正确地验证了签名。 log.error("微信对签名探测流量验证"); } log.info("-------------------WxPay---------GetHeader--------------------ENDING"); // 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048 RequestParam requestParam = new RequestParam.Builder() .serialNumber(serialNo) .nonce(nonce) .signature(signature) .timestamp(timestamp) .signType(signType) .body(notify) .build(); return requestParam; } public void saveCallbackInfo(UserPaymentDTO dto, String orderStatus){ String orderId = dto.getOrderId(); boolean lock = lockService.getObjectLock(RedisLockService.LOCK_KEY_PAYMENT_NOTIFY_, orderId); if(!lock){ return; } try { UserPayment up = userPaymentMapper.selectOne( new QueryWrapper().eq("order_id", orderId)); BeanUtils.copyProperties(dto, up); up.setPaymentTimeCallback(LocalDateTime.now()); userPaymentMapper.updateById(up); Order order = orderMapper.selectById(orderId); if(Constants.ORDER_STATUS_BACKEND.PAYMENT.name().equals(orderStatus)) { order.setPaymentTrId(dto.getTransactionId()); if (up.getPaymentAmountCallback() != null) { order.setPaymentAmount(new BigDecimal(up.getPaymentAmountCallback()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));//转换成单位元 } else { order.setPaymentAmount(order.getTotalAmount()); } order.setPaymentTime(up.getPaymentTimeCallback()); order.setStatus(Constants.ORDER_STATUS.SEND.name()); } else if (Constants.ORDER_STATUS_BACKEND.CANCEL.name().equals(orderStatus)){ order.setStatus(Constants.ORDER_STATUS.CANCEL.name()); } order.setStatusBackend(orderStatus); orderMapper.updateById(order); if(Constants.ORDER_STATUS_BACKEND.PAYMENT.name().equals(orderStatus)) { postPayment(order); } else if (Constants.ORDER_STATUS_BACKEND.CANCEL.name().equals(orderStatus)){ releasePrepayLock(order); } } catch (Exception e) { log.error(e.getMessage(), e); } finally { lockService.releaseObjectLock(RedisLockService.LOCK_KEY_PAYMENT_NOTIFY_, orderId); } } private void postPayment(Order order){ log.info("回调后处理订单信息:" + toJSONString(order)); //创建配送单 deliveryOrderService.createDeliveryOrder(order); flowerService.updateFlowerSales(order); } public Transaction queryOrder(String outTradeNo){ QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest(); request.setOutTradeNo(outTradeNo); request.setMchid(PyamentV3Configurer.merchantId); // 调用接口 return jsapiService.queryOrderByOutTradeNo(request); } public boolean checkOrderStatus(String outTradeNo){ return checkOrderStatus(outTradeNo, false); } public boolean checkOrderStatus(String outTradeNo, boolean isPayAgain){ UserPayment up = userPaymentMapper.selectOne( new QueryWrapper().eq("order_id", outTradeNo)); String s = up.getStatus(); if(StringUtils.isNotEmpty(s)){ return true; } Transaction transaction = queryOrder(outTradeNo); /* 交易成功判断条件: return_code、result_code和trade_state都为SUCCESS SUCCESS--支付成功 REFUND--转入退款 NOTPAY--未支付 CLOSED--已关闭 REVOKED--已撤销(刷卡支付) USERPAYING--用户支付中 PAYERROR--支付失败(其他原因,如银行返回失败) ACCEPT--已接收,等待扣款 */ String originalXml = toJSONString(transaction);//回调请求内容 log.info("message: " + originalXml); Transaction.TradeStateEnum tradeState = transaction.getTradeState(); String transactionId = transaction.getTransactionId();//事务处理id String orderId = outTradeNo; if(Transaction.TradeStateEnum.SUCCESS.equals(tradeState) || Transaction.TradeStateEnum.CLOSED.equals(tradeState)) { UserPaymentDTO dto = new UserPaymentDTO(); dto.setOrderId(orderId); dto.setTransactionId(transactionId); dto.setOutTradeNo(outTradeNo); dto.setOriginalXml(originalXml); TransactionAmount amount = transaction.getAmount(); if(amount != null) { Integer paymentAmountCallback = amount.getTotal();//实际支付金额 单位:分 log.info("======paymentAmountCallback: " + paymentAmountCallback); dto.setPaymentAmountCallback(paymentAmountCallback + ""); } dto.setStatus(tradeState.name()); String orderStatus = Transaction.TradeStateEnum.CLOSED.equals(tradeState) ? Constants.ORDER_STATUS_BACKEND.CANCEL.name() : Constants.ORDER_STATUS_BACKEND.PAYMENT.name(); saveCallbackInfo(dto, orderStatus); return true; } if(isPayAgain){ return !Transaction.TradeStateEnum.NOTPAY.equals(tradeState); } return false; } public void cancelOrder(String orderId){ UserPayment up = userPaymentMapper.selectOne( new QueryWrapper().eq("order_id", orderId)); if(StringUtils.isNotEmpty(up.getStatus())){ throw new ValidationException("订单不可取消"); } CloseOrderRequest request = new CloseOrderRequest(); request.setOutTradeNo(orderId); request.setMchid(PyamentV3Configurer.merchantId); // 调用接口 jsapiService.closeOrder(request); Order order = orderMapper.selectById(orderId); order.setStatus(Constants.ORDER_STATUS.CANCEL.name()); order.setStatusBackend(Constants.ORDER_STATUS_BACKEND.CANCEL.name()); order.setCancelTime(LocalDateTime.now()); order.update(SecurityUtils.getUserId()); orderMapper.updateById(order); up.setStatus(Constants.PAYMENT_STATUS.CLOSED.name()); up.update(SecurityUtils.getUserId()); userPaymentMapper.updateById(up); releasePrepayLock(order); } private void releasePrepayLock(Order order){ log.info("恢复库存: " + order); revertFlowerStock(order.getId()); } public Map payAgain(String orderId){ UserPayment up = userPaymentMapper.selectOne( new QueryWrapper().eq("order_id", orderId)); if(StringUtils.isNotEmpty(up.getStatus())){ throw new ValidationException("订单不可再支付"); } PrepayWithRequestPaymentResponse response = parseObject(up.getPrepayResponse() , PrepayWithRequestPaymentResponse.class); Map map = new HashMap<>(); map.put("appId", response.getAppId()); map.put("timeStamp", response.getTimeStamp()); map.put("nonceStr", response.getNonceStr()); map.put("package", response.getPackageVal()); map.put("signType", response.getSignType()); map.put("paySign", response.getPaySign()); return map; } public synchronized void revertFlowerStock(String orderId){ List ls = orderItemMapper.selectList(new QueryWrapper() .eq("order_id", orderId)); for(OrderItem c : ls){ flowerMapper.addFlowerStock(c.getFlowerId(), c.getNum()); } } /** * 退款 * * @param orderId */ public void refundOrder(String orderId){ Order o = orderMapper.selectById(orderId); /*String status = o.getStatusBackend(); if(!Constants.ORDER_STATUS_BACKEND.PAYMENT.name().equals(status)){ throw new ValidationException("未支付订单不可申请退款"); }*/ CreateRequest request = new CreateRequest(); request.setOutTradeNo(orderId); request.setOutRefundNo(UUIDGenerator.getUUID()); request.setTransactionId(o.getPaymentTrId()); request.setNotifyUrl(PyamentV3Configurer.notify_url_refund); AmountReq amount = new AmountReq(); int oa = prepareAmount(o.getPaymentAmount()); amount.setTotal((long)oa); amount.setRefund((long)oa); amount.setCurrency("CNY"); request.setAmount(amount); // 调用接口 refundService.create(request); o.setRefundAmount(o.getPaymentAmount()); o.setRefundNo(request.getOutRefundNo()); o.setRefundTime(LocalDateTime.now()); o.setStatus(Constants.ORDER_STATUS.REFUND.name()); o.setStatusBackend(Constants.ORDER_STATUS_BACKEND.REFUND.name()); o.update("sys"); orderMapper.updateById(o); deliveryOrderService.refundDelete(orderId); releasePrepayLock(o); } public String refundOrderSub(Order o, BigDecimal refundAmount){ if(o.getPaymentTime() == null || o.getPaymentAmount() == null){ throw new ValidationException("未支付订单不可退款"); } if(o.getRefundTime() != null){ throw new ValidationException("已全额退款订单不可退款"); } if (refundAmount == null || refundAmount.doubleValue() == 0) { throw new ValidationException("退款金额不能为空"); } List reLs = orderRefundMapper.selectList(new QueryWrapper() .eq("order_id", o.getId())); BigDecimal rra = new BigDecimal(0); if(reLs != null && reLs.size() > 0){ for(OrderRefund r : reLs){ rra = rra.add(r.getRefundAmount()); } } long total = (long)prepareAmount(o.getPaymentAmount()); long refund = (long)prepareAmount(refundAmount); long rraa = (long)prepareAmount(rra); if(rraa + refund > total){ throw new ValidationException("退款金额不能大于订单金额"); } OrderRefund re = new OrderRefund(); re.setId(UUIDGenerator.getUUID()); re.setOrderId(o.getId()); re.setOrderAmount(o.getPaymentAmount()); re.setRefundAmount(refundAmount); CreateRequest request = new CreateRequest(); request.setOutTradeNo(o.getId()); request.setOutRefundNo(re.getId()); request.setTransactionId(o.getPaymentTrId()); request.setNotifyUrl(PyamentV3Configurer.notify_url_refund); AmountReq amount = new AmountReq(); amount.setTotal(total); amount.setRefund(refund); amount.setCurrency("CNY"); request.setAmount(amount); // 调用接口 Refund refund1 = refundService.create(request); re.setRequest(toJSONString(refund1)); re.create(SecurityUtils.getUserId()); orderRefundMapper.insert(re); return re.getId(); } /** * 查询退款 * * @param orderId * @return */ public Refund refundQuery(String orderId){ Order o = orderMapper.selectById(orderId); if(StringUtils.isEmpty(o.getRefundNo())){ throw new ValidationException("该订单没有退款"); } QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest(); request.setOutRefundNo(orderId); // 调用接口 return refundService.queryByOutRefundNo(request); } public ResponseEntity handleRefundCallback(HttpServletRequest request) { try { ServletInputStream inputStream = request.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); // 读取请求体 StringBuilder sb = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { sb.append(line); } String notify = sb.toString(); log.info("微信退款通知: {}", notify); RequestParam requestParam = buildByHeaderRequestParam(request, notify); // 调用 NotificationParser.parse() 验签、解密并将 JSON 转换成具体的通知回调对象。如果验签失败,SDK 会抛出 ValidationException。 log.info("退款通知回调:验签、解密并转换成 RefundNotification对象:-------"); /** * 常用的通知回调调对象类型有: * 支付 Transaction * 退款 RefundNotification * 若 SDK 暂不支持的类型,请使用 Map.class,嵌套的 Json 对象将被转换成 LinkedTreeMap */ RefundNotification refundNotification; try { refundNotification = notificationParser.parse(requestParam, RefundNotification.class); } catch (ValidationException e) { // 签名验证失败,返回 401 UNAUTHORIZED 状态码 log.error("sign verification failed", e); return new ResponseEntity<>("", HttpStatus.UNAUTHORIZED); } log.info("Transaction:===>>>>退款CallBack状态" + refundNotification.getRefundStatus()); String outRefundNo = refundNotification.getOutRefundNo(); OrderRefund re = orderRefundMapper.selectById(outRefundNo); if(re != null) { re.setStatus(refundNotification.getRefundStatus().name()); re.setNotification(toJSONString(refundNotification)); re.setNotifyTime(LocalDateTime.now()); orderRefundMapper.updateById(re); } } catch (Exception e) { log.error("解析退款通知出错:{}", e.getMessage(), e); return new ResponseEntity<>("", HttpStatus.INTERNAL_SERVER_ERROR); } return new ResponseEntity<>("", HttpStatus.OK); } /** * 商家转账 * * @return */ public String doBatchTransfer(TransferReqDTO dto, String userId) { Transfer transfer = new Transfer(); transfer.setId(StringUtils.isNotEmpty(dto.getId()) ? dto.getId() : UUIDGenerator.getUUID()); transfer.setName(dto.getName()); transfer.setRemarks(dto.getRemarks()); InitiateBatchTransferRequest request = new InitiateBatchTransferRequest(); request.setAppid(dto.getAppId()); request.setOutBatchNo(transfer.getId());//【商家批次单号】 商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一 request.setBatchName(transfer.getName());//【批次名称】 该笔批量转账的名称 request.setBatchRemark(transfer.getRemarks());//【批次备注】 转账说明,UTF8编码,最多允许32个字符 List details = dto.getDetails(); transfer.setTotalNum(details.size()); Long totalAmount = 0L; for(TransferDetailReqDTO d : details) { TransferDetail td = new TransferDetail(); td.setId(StringUtils.isNotEmpty(d.getId()) ? d.getId() : UUIDGenerator.getUUID()); td.setTransferId(transfer.getId()); td.setAmount(d.getAmount()); td.setRemarks(d.getRemarks()); td.setUserName(d.getUserName()); td.setOpenId(d.getOpenId()); td.create(userId); transferDetailMapper.insert(td); totalAmount += td.getAmount(); TransferDetailInput di = new TransferDetailInput(); di.setOutDetailNo(td.getId());//【商家明细单号】 商户系统内部区分转账批次单下不同转账明细单的唯一标识,要求此参数只能由数字、大小写字母组成 di.setTransferAmount(td.getAmount());//【转账金额】 转账金额单位为“分” di.setTransferRemark(td.getRemarks());//【转账备注】 单条转账备注(微信用户会收到该备注),UTF8编码,最多允许32个字符 di.setOpenid(td.getOpenId()); di.setUserName(td.getUserName());//【收款用户姓名】 收款方真实姓名。明细转账金额<0.3元时,不允许填写收款用户姓名。明细转账金额 >= 2,000元,该笔明细必须填写收款用户姓名 request.getTransferDetailList().add(di); } transfer.setTotalAmount(totalAmount); request.setTotalAmount(transfer.getTotalAmount());//【转账总金额】 转账金额单位为“分”。转账总金额必须与批次内所有明细转账金额之和保持一致,否则无法发起转账操作 request.setTotalNum(transfer.getTotalNum());//【转账总笔数】 一个转账批次单最多发起一千笔转账。转账总笔数必须与批次内所有明细之和保持一致,否则无法发起转账操作 //ACCEPTED:已受理。批次已受理成功,若发起批量转账的30分钟后,转账批次单仍处于该状态,可能原因是商户账户余额不足等。商户可查询账户资金流水,若该笔转账批次单的扣款已经发生,则表示批次已经进入转账中,请再次查单确认 //PROCESSING:转账中。已开始处理批次内的转账明细单 //FINISHED:已完成。批次内的所有转账明细单都已处理完成 //CLOSED:已关闭。可查询具体的批次关闭原因确认 InitiateBatchTransferResponse r = transferBatchService.initiateBatchTransfer(request); transfer.setBatchId(r.getBatchId()); transfer.setStatus(r.getBatchStatus()); transfer.create(userId); transferMapper.insert(transfer); return transfer.getId(); } public void checkTransferStatus(Transfer transfer) {//定时任务验证转账状态 GetTransferBatchByOutNoRequest request = new GetTransferBatchByOutNoRequest(); request.setOutBatchNo(transfer.getId()); request.setNeedQueryDetail(true); request.setDetailStatus("ALL"); TransferBatchEntity tb = transferBatchService.getTransferBatchByOutNo(request); transfer.setCheckLog(toJSONString(tb)); transfer.setCheckTime(LocalDateTime.now()); TransferBatchGet b = tb.getTransferBatch(); transfer.setStatus(b.getBatchStatus()); transfer.update("sys"); transferMapper.updateById(transfer); List dLs = tb.getTransferDetailList(); if(dLs != null && dLs.size() > 0) { for (TransferDetailCompact d : dLs) { TransferDetail td = transferDetailMapper.selectById(d.getOutDetailNo()); td.setStatus(d.getDetailStatus()); td.update("sys"); transferDetailMapper.updateById(td); } } } public List getUnCompletedTransfer(){//定时任务验证转账状态 List statusList = new ArrayList<>(); statusList.add(Constants.TRANSFER_STATUS.ACCEPTED.name()); statusList.add(Constants.TRANSFER_STATUS.PROCESSING.name()); return transferMapper.selectList(new QueryWrapper() .in("status", statusList) ); } }