Commit 25667a05 authored by xiaoyu's avatar xiaoyu
Browse files

分账结果查询,定时任务逻辑

parent 56bc6dc8
......@@ -18,11 +18,10 @@ package com.jeequan.jeepay.pay.channel;
import com.jeequan.jeepay.core.entity.MchDivisionReceiver;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.core.entity.TransferOrder;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.rqrs.transfer.TransferOrderRQ;
import java.util.HashMap;
import java.util.List;
/**
......@@ -46,4 +45,7 @@ public interface IDivisionService {
/** 单次分账 (无需调用完结接口,或自动解冻商户资金) **/
ChannelRetMsg singleDivision(PayOrder payOrder, List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext);
/** 查询分账结果 **/
HashMap<Long, ChannelRetMsg> queryDivision(PayOrder payOrder, List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext);
}
......@@ -15,16 +15,20 @@
*/
package com.jeequan.jeepay.pay.channel.alipay;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.domain.*;
import com.alipay.api.request.AlipayTradeOrderSettleQueryRequest;
import com.alipay.api.request.AlipayTradeOrderSettleRequest;
import com.alipay.api.request.AlipayTradeRoyaltyRelationBindRequest;
import com.alipay.api.response.AlipayTradeOrderSettleQueryResponse;
import com.alipay.api.response.AlipayTradeOrderSettleResponse;
import com.alipay.api.response.AlipayTradeRoyaltyRelationBindResponse;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchDivisionReceiver;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.utils.AmountUtil;
import com.jeequan.jeepay.core.utils.RegKit;
import com.jeequan.jeepay.core.utils.SeqKit;
......@@ -39,6 +43,7 @@ import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
/**
......@@ -205,4 +210,86 @@ public class AlipayDivisionService implements IDivisionService {
}
}
@Override
public HashMap<Long, ChannelRetMsg> queryDivision(PayOrder payOrder, List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext) {
// 创建返回结果
HashMap<Long, ChannelRetMsg> resultMap = new HashMap<>();
// 同批次分账记录结果集
HashMap<String, RoyaltyDetail> aliAcMap = new HashMap<>();
try {
// 当无分账用户时, 支付宝不允许发起分账请求, 支付宝没有完结接口,直接响应成功即可。
if(recordList.isEmpty()){
throw new BizException("payOrderId:" + payOrder.getPayOrderId() + "分账记录为空。recordList:" + recordList);
}
AlipayTradeOrderSettleQueryRequest request = new AlipayTradeOrderSettleQueryRequest();
AlipayTradeOrderSettleQueryModel model = new AlipayTradeOrderSettleQueryModel();
request.setBizModel(model);
//统一放置 isv接口必传信息
AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model);
// 支付宝分账请求单号
model.setSettleNo(recordList.get(0).getBatchOrderId());
//结算请求流水号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。
model.setOutRequestNo(payOrder.getPayOrderId());
//支付宝订单号
model.setTradeNo(payOrder.getChannelOrderNo());
//调起支付宝分账接口
if(log.isInfoEnabled()){
log.info("订单:[{}], 支付宝查询分账请求:{}", recordList.get(0).getBatchOrderId(), JSON.toJSONString(model));
}
AlipayTradeOrderSettleQueryResponse alipayResp = configContextQueryService.getAlipayClientWrapper(mchAppConfigContext).execute(request);
log.info("订单:[{}], 支付宝查询分账响应:{}", payOrder.getPayOrderId(), alipayResp.getBody());
if(alipayResp.isSuccess()){
List<RoyaltyDetail> detailList = alipayResp.getRoyaltyDetailList();
if (CollectionUtil.isNotEmpty(detailList)) {
// 遍历匹配与当前账户相同的分账单
detailList.stream().forEach(item -> {
// 分账操作类型为转账类型
if ("transfer".equals(item.getOperationType())) {
aliAcMap.put(item.getTransIn(), item);
}
});
}
}else {
log.error("支付宝分账查询响应异常, alipayResp:{}", JSON.toJSONString(alipayResp));
throw new BizException("支付宝分账查询响应异常:" + alipayResp.getSubMsg());
}
// 返回结果
recordList.stream().forEach(record -> {
// 对应入账账号匹配
if (aliAcMap.get(record.getAccNo()) != null) {
RoyaltyDetail detail = aliAcMap.get(record.getAccNo());
ChannelRetMsg channelRetMsg = new ChannelRetMsg();
// 错误码
channelRetMsg.setChannelErrCode(detail.getErrorCode());
// 错误信息
channelRetMsg.setChannelErrMsg(detail.getErrorDesc());
// 仅返回分账记录为最终态的结果 处理中的分账单不做返回处理
if ("SUCCESS".equals(detail.getState())) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
resultMap.put(record.getRecordId(), channelRetMsg);
}else if ("FAIL".equals(detail.getState())) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
resultMap.put(record.getRecordId(), channelRetMsg);
}
}
});
}catch (Exception e) {
log.error("查询分账信息异常", e);
throw new BizException(e.getMessage());
}
return resultMap;
}
}
......@@ -15,6 +15,7 @@
*/
package com.jeequan.jeepay.pay.channel.wxpay;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.profitsharing.*;
......@@ -26,6 +27,7 @@ import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchDivisionReceiver;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.params.wxpay.WxpayIsvsubMchParams;
import com.jeequan.jeepay.core.utils.SeqKit;
import com.jeequan.jeepay.pay.channel.IDivisionService;
......@@ -38,8 +40,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
......@@ -246,6 +248,106 @@ public class WxpayDivisionService implements IDivisionService {
}
}
@Override
public HashMap<Long, ChannelRetMsg> queryDivision(PayOrder payOrder, List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext) {
// 创建返回结果
HashMap<Long, ChannelRetMsg> resultMap = new HashMap<>();
try {
// 当无分账用户时, 支付宝不允许发起分账请求, 支付宝没有完结接口,直接响应成功即可。
if(recordList.isEmpty()){
throw new BizException("payOrderId:" + payOrder.getPayOrderId() + "分账记录为空。recordList:" + recordList);
}
WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);
if (CS.PAY_IF_VERSION.WX_V2.equals(wxServiceWrapper.getApiVersion())) { //V2
// 同批次分账记录结果集
HashMap<String, ProfitSharingQueryResult.Receiver> wxAcMap = new HashMap<>();
ProfitSharingQueryRequest request = new ProfitSharingQueryRequest();
request.setTransactionId(payOrder.getChannelOrderNo());
//放置isv信息
WxpayKit.putApiIsvInfo(mchAppConfigContext, request);
request.setOutOrderNo(recordList.get(0).getBatchOrderId()); //取到批次号
ProfitSharingQueryResult profitSharingQueryResult = wxServiceWrapper.getWxPayService().getProfitSharingService().profitSharingQuery(request);
List<ProfitSharingQueryResult.Receiver> receivers = profitSharingQueryResult.getReceivers();
if (CollectionUtil.isNotEmpty(receivers)) {
// 遍历匹配与当前账户相同的分账单
receivers.stream().forEach(item -> {
wxAcMap.put(item.getAccount(), item);
});
}
recordList.stream().forEach(record -> {
ProfitSharingQueryResult.Receiver receiver = wxAcMap.get(record.getAccNo());
if (receiver != null) {
ChannelRetMsg channelRetMsg = new ChannelRetMsg();
// 错误信息
channelRetMsg.setChannelErrMsg(receiver.getFailReason());
if ("SUCCESS".equals(receiver.getResult())) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
resultMap.put(record.getRecordId(), channelRetMsg);
}else if ("CLOSED".equals(receiver.getResult())) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
resultMap.put(record.getRecordId(), channelRetMsg);
}
}
});
}else if (CS.PAY_IF_VERSION.WX_V3.equals(wxServiceWrapper.getApiVersion())) {
// 同批次分账记录结果集
HashMap<String, com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingResult.Receiver> wxAcMap = new HashMap<>();
// 发起请求
com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingResult profitSharingResult = wxServiceWrapper.getWxPayService().getProfitSharingV3Service().getProfitSharingResult(recordList.get(0).getBatchOrderId(), payOrder.getChannelOrderNo());
List<com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingResult.Receiver> receivers = profitSharingResult.getReceivers();
if (CollectionUtil.isNotEmpty(receivers)) {
// 遍历匹配与当前账户相同的分账单
receivers.stream().forEach(item -> {
wxAcMap.put(item.getAccount(), item);
});
}
recordList.stream().forEach(record -> {
com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingResult.Receiver receiver = wxAcMap.get(record.getAccNo());
if (receiver != null) {
ChannelRetMsg channelRetMsg = new ChannelRetMsg();
// 错误信息
channelRetMsg.setChannelErrMsg(receiver.getFailReason());
if ("SUCCESS".equals(receiver.getResult())) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
resultMap.put(record.getRecordId(), channelRetMsg);
}else if ("CLOSED".equals(receiver.getResult())) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
resultMap.put(record.getRecordId(), channelRetMsg);
}
}
});
}
} catch (WxPayException wxPayException) {
log.error("微信查询分账结果失败{}", wxPayException.getCustomErrorMsg());
throw new BizException(wxPayException.getCustomErrorMsg());
} catch (Exception e) {
log.error("微信分账失败", e);
throw new BizException(e.getMessage());
}
return resultMap;
}
/** 调用订单的完结接口 (分账对象不存在时) */
private String divisionFinish(PayOrder payOrder,MchAppConfigContext mchAppConfigContext) throws WxPayException {
......
......@@ -19,14 +19,22 @@ 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.PayOrder;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.pay.channel.IDivisionService;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.service.ConfigContextQueryService;
import com.jeequan.jeepay.service.impl.PayOrderDivisionRecordService;
import com.jeequan.jeepay.service.impl.PayOrderService;
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;
import java.util.HashMap;
import java.util.List;
/*
......@@ -43,6 +51,8 @@ public class PayOrderDivisionRecordReissueTask {
private static final int QUERY_PAGE_SIZE = 100; //每次查询数量
@Autowired private PayOrderDivisionRecordService payOrderDivisionRecordService;
@Autowired private ConfigContextQueryService configContextQueryService;
@Autowired private PayOrderService payOrderService;
@Scheduled(cron="0 0/1 * * * ?") // 每分钟执行一次
public void start() {
......@@ -61,7 +71,6 @@ public class PayOrderDivisionRecordReissueTask {
while(true){
try {
IPage<PayOrderDivisionRecord> pageRecordList = payOrderDivisionRecordService.getBaseMapper().distinctBatchOrderIdList(new Page(currentPageIndex, QUERY_PAGE_SIZE), lambdaQueryWrapper);
log.info("处理分账补单任务, 共计{}条", pageRecordList.getTotal());
......@@ -87,13 +96,44 @@ public class PayOrderDivisionRecordReissueTask {
continue;
}
// 查询支付订单信息
PayOrder payOrder = payOrderService.getById(batchRecord.getPayOrderId());
if (payOrder == null) {
log.error("支付订单记录不存在:{}", batchRecord.getPayOrderId());
continue;
}
// 查询转账接口是否存在
IDivisionService divisionService = SpringBeansUtil.getBean(batchRecord.getIfCode() + "DivisionService", IDivisionService.class);
if (divisionService == null) {
log.error("查询转账接口不存在:{}", batchRecord.getIfCode());
continue;
}
MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(payOrder.getMchNo(), payOrder.getAppId());
// 调用渠道侧的查单接口: 注意: 渠道内需保证:
// 1. 返回的条目 必须全部来自recordList, 可以少于recordList但是不得高于 recordList 数量;
// 2. recordList 的记录可能与接口返回的数量不一致, 接口实现不要求对条目数量做验证;
// 3. 接口查询的记录若recordList 不存在, 忽略即可。 ( 例如两条相同的accNo, 则可能仅匹配一条。 那么另外一条将在下一次循环中处理。 )
// 4. 仅明确状态的再返回,若不明确则不需返回;
HashMap<Long, ChannelRetMsg> queryDivision = divisionService.queryDivision(payOrder, recordList, mchAppConfigContext);
// 处理查询结果
recordList.stream().forEach(record -> {
ChannelRetMsg channelRetMsg = queryDivision.get(record.getRecordId());
// 响应状态为分账成功或失败时,更新该记录状态
if (ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState() ||
ChannelRetMsg.ChannelState.CONFIRM_FAIL == channelRetMsg.getChannelState()) {
PayOrderDivisionRecord upDivisionRecord = new PayOrderDivisionRecord();
upDivisionRecord.setRecordId(record.getRecordId());
upDivisionRecord.setChannelRespResult(channelRetMsg.getChannelErrMsg());
upDivisionRecord.setState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState() ? PayOrderDivisionRecord.STATE_SUCCESS : PayOrderDivisionRecord.STATE_FAIL);
// channelOrderReissueService.processPayOrder(payOrder);
// payOrderDivisionRecordService.updateRecordSuccessOrFail(upDivisionRecord);
}
});
} catch (Exception e1) {
log.error("处理补单任务单条[{}]异常", batchRecord.getBatchOrderId(), e1);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment