新增查询转账单状态,对接支付宝、微信转账查询接口
This commit is contained in:
parent
a4e4c990c3
commit
43e2669d24
|
|
@ -41,4 +41,7 @@ public interface ITransferService {
|
|||
/** 调起退款接口,并响应数据; 内部处理普通商户和服务商模式 **/
|
||||
ChannelRetMsg transfer(TransferOrderRQ bizRQ, TransferOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception;
|
||||
|
||||
/** 调起转账查询接口 **/
|
||||
ChannelRetMsg query(TransferOrder transferOrder, MchAppConfigContext mchAppConfigContext);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,12 @@
|
|||
*/
|
||||
package com.jeequan.jeepay.pay.channel.alipay;
|
||||
|
||||
import com.alipay.api.domain.AlipayFundTransCommonQueryModel;
|
||||
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
|
||||
import com.alipay.api.domain.Participant;
|
||||
import com.alipay.api.request.AlipayFundTransCommonQueryRequest;
|
||||
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
|
||||
import com.alipay.api.response.AlipayFundTransCommonQueryResponse;
|
||||
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
|
||||
import com.jeequan.jeepay.core.constants.CS;
|
||||
import com.jeequan.jeepay.core.entity.TransferOrder;
|
||||
|
|
@ -98,8 +101,17 @@ public class AlipayTransferService implements ITransferService {
|
|||
|
||||
// 调用成功
|
||||
if(response.isSuccess()){
|
||||
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
|
||||
channelRetMsg.setChannelOrderId(response.getOrderId());
|
||||
if ("SUCCESS".equals(response.getStatus())) {
|
||||
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
|
||||
channelRetMsg.setChannelOrderId(response.getOrderId());
|
||||
}else if ("FAIL".equals(response.getStatus())) {
|
||||
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
|
||||
channelRetMsg.setChannelErrCode(AlipayKit.appendErrCode(response.getCode(), response.getSubCode()));
|
||||
channelRetMsg.setChannelErrMsg(AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg()));
|
||||
}else {
|
||||
return ChannelRetMsg.waiting();
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
//若 系统繁忙, 无法确认结果
|
||||
|
|
@ -115,4 +127,38 @@ public class AlipayTransferService implements ITransferService {
|
|||
return channelRetMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelRetMsg query(TransferOrder transferOrder, MchAppConfigContext mchAppConfigContext) {
|
||||
|
||||
AlipayFundTransCommonQueryRequest request = new AlipayFundTransCommonQueryRequest();
|
||||
AlipayFundTransCommonQueryModel model = new AlipayFundTransCommonQueryModel();
|
||||
model.setProductCode(TransferOrder.ENTRY_BANK_CARD.equals(transferOrder.getEntryType()) ? "TRANS_BANKCARD_NO_PWD" : "TRANS_ACCOUNT_NO_PWD");
|
||||
model.setBizScene("DIRECT_TRANSFER");
|
||||
model.setOutBizNo(transferOrder.getTransferId()); // 商户转账唯一订单号
|
||||
|
||||
AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model);
|
||||
request.setBizModel(model);
|
||||
|
||||
// 调起支付宝接口
|
||||
AlipayFundTransCommonQueryResponse response = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(request);
|
||||
if (response.isSuccess()) {
|
||||
// SUCCESS,明确成功
|
||||
if("SUCCESS".equalsIgnoreCase(response.getStatus())){
|
||||
return ChannelRetMsg.confirmSuccess(response.getOrderId());
|
||||
}
|
||||
// REFUND:退票(适用于"单笔转账到银行卡"); FAIL:失败(适用于"单笔转账到银行卡")
|
||||
else if ("REFUND".equalsIgnoreCase(response.getStatus()) || "FAIL".equalsIgnoreCase(response.getStatus())){
|
||||
return ChannelRetMsg.confirmFail(response.getErrorCode(), response.getFailReason());
|
||||
} else{
|
||||
return ChannelRetMsg.waiting();
|
||||
}
|
||||
} else {
|
||||
// 如果查询单号对应的数据不存在,那么数据不存在的原因可能是:(1)付款还在处理中;(2)付款处理失败导致付款订单没有落地,务必再次查询确认此次付款的结果。
|
||||
if("ORDER_NOT_EXIST".equalsIgnoreCase(response.getSubCode())){
|
||||
return ChannelRetMsg.waiting();
|
||||
}
|
||||
return ChannelRetMsg.confirmFail(AlipayKit.appendErrCode(response.getCode(), response.getSubCode()), AlipayKit.appendErrMsg(response.getMsg(), response.getSubMsg()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,11 @@
|
|||
*/
|
||||
package com.jeequan.jeepay.pay.channel.wxpay;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.entpay.EntPayQueryRequest;
|
||||
import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult;
|
||||
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
|
||||
import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
|
||||
import com.github.binarywang.wxpay.bean.transfer.TransferBatchDetailResult;
|
||||
import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest;
|
||||
import com.github.binarywang.wxpay.bean.transfer.TransferBatchesResult;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
|
|
@ -110,13 +113,8 @@ public class WxpayTransferService implements ITransferService {
|
|||
}
|
||||
|
||||
EntPayResult entPayResult = wxServiceWrapper.getWxPayService().getEntPayService().entPay(request);
|
||||
return ChannelRetMsg.waiting();
|
||||
|
||||
// SUCCESS/FAIL,注意:当状态为FAIL时,存在业务结果未明确的情况。如果状态为FAIL,请务必关注错误代码(err_code字段),通过查询接口确认此次付款的结果。
|
||||
if("SUCCESS".equalsIgnoreCase(entPayResult.getResultCode())){
|
||||
return ChannelRetMsg.confirmSuccess(entPayResult.getPaymentNo());
|
||||
}else{
|
||||
return ChannelRetMsg.waiting();
|
||||
}
|
||||
} else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) {
|
||||
TransferBatchesRequest request = new TransferBatchesRequest();
|
||||
request.setAppid(wxServiceWrapper.getWxPayService().getConfig().getAppId());
|
||||
|
|
@ -137,7 +135,7 @@ public class WxpayTransferService implements ITransferService {
|
|||
request.setTransferDetailList(list);
|
||||
|
||||
TransferBatchesResult transferBatchesResult = wxServiceWrapper.getWxPayService().getTransferService().transferBatches(request);
|
||||
return ChannelRetMsg.confirmSuccess(transferBatchesResult.getBatchId());
|
||||
return ChannelRetMsg.waiting();
|
||||
} else {
|
||||
return ChannelRetMsg.sysError("请选择微信V2或V3模式");
|
||||
}
|
||||
|
|
@ -159,4 +157,56 @@ public class WxpayTransferService implements ITransferService {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelRetMsg query(TransferOrder transferOrder, MchAppConfigContext mchAppConfigContext) {
|
||||
|
||||
try {
|
||||
WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);
|
||||
|
||||
if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2
|
||||
|
||||
EntPayQueryResult entPayQueryResult = wxServiceWrapper.getWxPayService().getEntPayService().queryEntPay(transferOrder.getTransferId());
|
||||
|
||||
// SUCCESS,明确成功
|
||||
if("SUCCESS".equalsIgnoreCase(entPayQueryResult.getStatus())){
|
||||
return ChannelRetMsg.confirmSuccess(entPayQueryResult.getDetailId());
|
||||
} else if ("FAILED".equalsIgnoreCase(entPayQueryResult.getStatus())){ // FAILED,明确失败
|
||||
return ChannelRetMsg.confirmFail(entPayQueryResult.getStatus(), entPayQueryResult.getReason());
|
||||
} else{
|
||||
return ChannelRetMsg.waiting();
|
||||
}
|
||||
} else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) {
|
||||
|
||||
TransferBatchDetailResult transferBatchDetailResult =
|
||||
wxServiceWrapper.getWxPayService().getTransferService().transferBatchesOutBatchNoDetail(transferOrder.getTransferId(), transferOrder.getTransferId());
|
||||
|
||||
// SUCCESS,明确成功
|
||||
if("SUCCESS".equalsIgnoreCase(transferBatchDetailResult.getDetailStatus())){
|
||||
return ChannelRetMsg.confirmSuccess(transferBatchDetailResult.getDetailId());
|
||||
} else if ("FAIL".equalsIgnoreCase(transferBatchDetailResult.getDetailStatus())){ // FAIL,明确失败
|
||||
return ChannelRetMsg.confirmFail(transferBatchDetailResult.getDetailStatus(), transferBatchDetailResult.getFailReason());
|
||||
} else{
|
||||
return ChannelRetMsg.waiting();
|
||||
}
|
||||
} else {
|
||||
return ChannelRetMsg.sysError("请选择微信V2或V3模式");
|
||||
}
|
||||
|
||||
} catch (WxPayException e) {
|
||||
|
||||
// 如果查询单号对应的数据不存在,那么数据不存在的原因可能是:(1)付款还在处理中;(2)付款处理失败导致付款订单没有落地,务必再次查询确认此次付款的结果。
|
||||
if("NOT_FOUND".equalsIgnoreCase(e.getErrCode())){
|
||||
return ChannelRetMsg.waiting();
|
||||
}
|
||||
|
||||
return ChannelRetMsg.confirmFail(null,
|
||||
WxpayKit.appendErrCode(e.getReturnMsg(), e.getErrCode()),
|
||||
WxpayKit.appendErrMsg(e.getReturnMsg(), StringUtils.defaultIfEmpty(e.getErrCodeDes(), e.getCustomErrorMsg())));
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("转账状态查询异常:", e);
|
||||
return ChannelRetMsg.waiting();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jeequan.jeepay.pay.service;
|
||||
|
||||
import com.jeequan.jeepay.core.entity.TransferOrder;
|
||||
import com.jeequan.jeepay.core.exception.BizException;
|
||||
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
|
||||
import com.jeequan.jeepay.pay.channel.ITransferService;
|
||||
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
|
||||
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
|
||||
import com.jeequan.jeepay.service.impl.TransferOrderService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/*
|
||||
* 转账补单服务实现类
|
||||
*
|
||||
* @author zx
|
||||
* @site https://www.jeequan.com
|
||||
* @date 2022/12/29 17:47
|
||||
*/
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class TransferOrderReissueService {
|
||||
|
||||
@Autowired private ConfigContextQueryService configContextQueryService;
|
||||
@Autowired private TransferOrderService transferOrderService;
|
||||
@Autowired private PayMchNotifyService payMchNotifyService;
|
||||
|
||||
|
||||
/** 处理转账订单 **/
|
||||
public ChannelRetMsg processOrder(TransferOrder transferOrder){
|
||||
|
||||
try {
|
||||
|
||||
String transferId = transferOrder.getTransferId();
|
||||
|
||||
// 查询转账接口是否存在
|
||||
ITransferService transferService = SpringBeansUtil.getBean(transferOrder.getIfCode() + "TransferService", ITransferService.class);
|
||||
|
||||
// 支付通道转账接口实现不存在
|
||||
if(transferService == null){
|
||||
log.error("{} interface not exists!", transferOrder.getIfCode());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 查询出商户应用的配置信息
|
||||
MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(transferOrder.getMchNo(), transferOrder.getAppId());
|
||||
|
||||
ChannelRetMsg channelRetMsg = transferService.query(transferOrder, mchAppConfigContext);
|
||||
if(channelRetMsg == null){
|
||||
log.error("channelRetMsg is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
log.info("补单[{}]查询结果为:{}", transferId, channelRetMsg);
|
||||
|
||||
// 查询成功
|
||||
if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS) {
|
||||
// 转账成功
|
||||
transferOrderService.updateIng2Success(transferId, channelRetMsg.getChannelOrderId());
|
||||
payMchNotifyService.transferOrderNotify(transferOrderService.getById(transferId));
|
||||
|
||||
}else if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_FAIL){
|
||||
// 转账失败
|
||||
transferOrderService.updateIng2Fail(transferId, channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelUserId(), channelRetMsg.getChannelErrCode());
|
||||
payMchNotifyService.transferOrderNotify(transferOrderService.getById(transferId));
|
||||
}
|
||||
|
||||
return channelRetMsg;
|
||||
|
||||
} catch (Exception e) { //继续下一次迭代查询
|
||||
log.error("error transferId = {}", transferOrder.getTransferId(), e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理返回的渠道信息,并更新订单状态
|
||||
* TransferOrder将对部分信息进行 赋值操作。
|
||||
* **/
|
||||
public void processChannelMsg(ChannelRetMsg channelRetMsg, TransferOrder transferOrder){
|
||||
|
||||
//对象为空 || 上游返回状态为空, 则无需操作
|
||||
if(channelRetMsg == null || channelRetMsg.getChannelState() == null){
|
||||
return ;
|
||||
}
|
||||
|
||||
//明确成功
|
||||
if(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState()) {
|
||||
|
||||
this.updateInitOrderStateThrowException(TransferOrder.STATE_SUCCESS, transferOrder, channelRetMsg);
|
||||
payMchNotifyService.transferOrderNotify(transferOrderService.getById(transferOrder.getTransferId()));
|
||||
|
||||
//明确失败
|
||||
}else if(ChannelRetMsg.ChannelState.CONFIRM_FAIL == channelRetMsg.getChannelState()) {
|
||||
|
||||
this.updateInitOrderStateThrowException(TransferOrder.STATE_FAIL, transferOrder, channelRetMsg);
|
||||
payMchNotifyService.transferOrderNotify(transferOrderService.getById(transferOrder.getTransferId()));
|
||||
|
||||
// 上游处理中 || 未知 || 上游接口返回异常 订单为支付中状态
|
||||
}else if( ChannelRetMsg.ChannelState.WAITING == channelRetMsg.getChannelState() ||
|
||||
ChannelRetMsg.ChannelState.UNKNOWN == channelRetMsg.getChannelState() ||
|
||||
ChannelRetMsg.ChannelState.API_RET_ERROR == channelRetMsg.getChannelState()
|
||||
|
||||
){
|
||||
this.updateInitOrderStateThrowException(TransferOrder.STATE_ING, transferOrder, channelRetMsg);
|
||||
|
||||
// 系统异常: 订单不再处理。 为: 生成状态
|
||||
}else if( ChannelRetMsg.ChannelState.SYS_ERROR == channelRetMsg.getChannelState()){
|
||||
|
||||
}else{
|
||||
|
||||
throw new BizException("ChannelState 返回异常!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** 更新转账单状态 --》 转账单生成--》 其他状态 (向外抛出异常) **/
|
||||
private void updateInitOrderStateThrowException(byte orderState, TransferOrder transferOrder, ChannelRetMsg channelRetMsg){
|
||||
|
||||
transferOrder.setState(orderState);
|
||||
transferOrder.setChannelOrderNo(channelRetMsg.getChannelOrderId());
|
||||
transferOrder.setErrCode(channelRetMsg.getChannelErrCode());
|
||||
transferOrder.setErrMsg(channelRetMsg.getChannelErrMsg());
|
||||
|
||||
boolean isSuccess = transferOrderService.updateInit2Ing(transferOrder.getTransferId());
|
||||
if(!isSuccess){
|
||||
throw new BizException("更新转账单异常!");
|
||||
}
|
||||
|
||||
isSuccess = transferOrderService.updateIng2SuccessOrFail(transferOrder.getTransferId(), transferOrder.getState(),
|
||||
channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelErrCode(), channelRetMsg.getChannelErrMsg());
|
||||
if(!isSuccess){
|
||||
throw new BizException("更新转账订单异常!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.jeequan.jeepay.pay.task;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.jeequan.jeepay.core.entity.TransferOrder;
|
||||
import com.jeequan.jeepay.pay.service.TransferOrderReissueService;
|
||||
import com.jeequan.jeepay.service.impl.TransferOrderService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/*
|
||||
* 转账补单定时任务
|
||||
*
|
||||
* @author zx
|
||||
* @site https://www.jeequan.com
|
||||
* @date 2022/12/29 17:47
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class TransferOrderReissueTask {
|
||||
|
||||
private static final int QUERY_PAGE_SIZE = 100; //每次查询数量
|
||||
|
||||
@Autowired private TransferOrderService transferOrderService;
|
||||
@Autowired private TransferOrderReissueService transferOrderReissueService;
|
||||
|
||||
@Scheduled(cron="0 0/1 * * * ?") // 每分钟执行一次
|
||||
public void start() {
|
||||
|
||||
//查询条件:
|
||||
LambdaQueryWrapper<TransferOrder> lambdaQueryWrapper = TransferOrder.gw()
|
||||
.eq(TransferOrder::getState, TransferOrder.STATE_ING) // 转账中
|
||||
.ge(TransferOrder::getCreatedAt, DateUtil.offsetDay(new Date(), -1)); // 只查询一天内的转账单;
|
||||
|
||||
int currentPageIndex = 1; //当前页码
|
||||
while(true){
|
||||
|
||||
try {
|
||||
IPage<TransferOrder> iPage = transferOrderService.page(new Page(currentPageIndex, QUERY_PAGE_SIZE), lambdaQueryWrapper);
|
||||
|
||||
if(iPage == null || iPage.getRecords().isEmpty()){ //本次查询无结果, 不再继续查询;
|
||||
break;
|
||||
}
|
||||
|
||||
for(TransferOrder transferOrder: iPage.getRecords()){
|
||||
transferOrderReissueService.processOrder(transferOrder);
|
||||
}
|
||||
|
||||
//已经到达页码最大量,无需再次查询
|
||||
if(iPage.getPages() <= currentPageIndex){
|
||||
break;
|
||||
}
|
||||
currentPageIndex++;
|
||||
|
||||
} catch (Exception e) { //出现异常,直接退出,避免死循环。
|
||||
log.error("error", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue