Commit c87405c3 authored by terrfly's avatar terrfly
Browse files

添加分账异步通知机制, 添加完成支付宝回调处理事件。

parent 25667a05
/*
* 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.channel;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.beans.RequestKitBean;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.DivisionChannelNotifyModel;
import com.jeequan.jeepay.pay.service.ConfigContextQueryService;
import com.jeequan.jeepay.pay.util.ChannelCertConfigKitBean;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.List;
/*
* 分账结果回调接口抽象类
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2023/3/29 15:39
*/
public abstract class AbstractDivisionRecordChannelNotifyService {
@Autowired private RequestKitBean requestKitBean;
@Autowired private ChannelCertConfigKitBean channelCertConfigKitBean;
@Autowired protected ConfigContextQueryService configContextQueryService;
/** 获取到接口code **/
public abstract String getIfCode();
/** 解析参数: 批次号 和 请求参数
* 异常需要自行捕捉,并返回null , 表示已响应数据。
* **/
public abstract MutablePair<String, Object> parseParams(HttpServletRequest request);
/**
* 返回需要更新的记录 <ID, 结果> 状态 和响应数据
*
* **/
public abstract DivisionChannelNotifyModel doNotify(HttpServletRequest request, Object params,
List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext);
public ResponseEntity doNotifyOrderNotExists(HttpServletRequest request) {
return textResp("order not exists");
}
public ResponseEntity doNotifyOrderStateUpdateFail(HttpServletRequest request) {
return textResp("update status error");
}
/** 文本类型的响应数据 **/
protected ResponseEntity textResp(String text){
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.TEXT_HTML);
return new ResponseEntity(text, httpHeaders, HttpStatus.OK);
}
/** json类型的响应数据 **/
protected ResponseEntity jsonResp(Object body){
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity(body, httpHeaders, HttpStatus.OK);
}
/**request.getParameter 获取参数 并转换为JSON格式 **/
protected JSONObject getReqParamJSON() {
return requestKitBean.getReqParamJSON();
}
/**request.getParameter 获取参数 并转换为JSON格式 **/
protected String getReqParamFromBody() {
return requestKitBean.getReqParamFromBody();
}
/** 获取文件路径 **/
protected String getCertFilePath(String certFilePath) {
return channelCertConfigKitBean.getCertFilePath(certFilePath);
}
/** 获取文件File对象 **/
protected File getCertFile(String certFilePath) {
return channelCertConfigKitBean.getCertFile(certFilePath);
}
}
/*
* 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.channel.alipay;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.AlipaySignature;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.core.exception.ResponseException;
import com.jeequan.jeepay.core.model.params.alipay.AlipayConfig;
import com.jeequan.jeepay.core.model.params.alipay.AlipayIsvParams;
import com.jeequan.jeepay.core.model.params.alipay.AlipayNormalMchParams;
import com.jeequan.jeepay.pay.channel.AbstractDivisionRecordChannelNotifyService;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.rqrs.msg.DivisionChannelNotifyModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/*
* 支付宝 分账回调接口实现类
*
* 注意:
*
// royalty_mode 必须传入: async ( 使用异步: 需要 1、请配置 支付宝应用的网关地址 ( xxx.com/api/channelbiz/alipay/appGatewayMsgReceive ), 2、 订阅消息。 )
// 2023-03-30 咨询支付宝客服: 如果没有传royalty_mode分账模式,这个默认会是同步分账,同步分账不需要关注异步通知,接口调用成功就分账成功了 2,同步分账默认不会给您发送异步通知。
// 3. 服务商代商户调用商家分账,当异步分账时服务商必须调用alipay.open.app.message.topic.subscribe(订阅消息主题)对消息api做关联绑定,服务商才会收到alipay.trade.order.settle.notify通知,否则服务商无法收到通知。
// https://opendocs.alipay.com/open/20190308105425129272/quickstart#%E8%9A%82%E8%9A%81%E6%B6%88%E6%81%AF%EF%BC%9A%E4%BA%A4%E6%98%93%E5%88%86%E8%B4%A6%E7%BB%93%E6%9E%9C%E9%80%9A%E7%9F%A5
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2023/3/30 12:20
*/
@Service
@Slf4j
public class AlipayDivisionRecordChannelNotifyService extends AbstractDivisionRecordChannelNotifyService {
@Override
public String getIfCode() {
return CS.IF_CODE.ALIPAY;
}
@Override
public MutablePair<String, Object> parseParams(HttpServletRequest request) {
try {
JSONObject params = getReqParamJSON();
String batchOrderId = params.getJSONObject("biz_content").getString("out_request_no"); // 分账批次号
return MutablePair.of(batchOrderId, params);
} catch (Exception e) {
log.error("error", e);
throw ResponseException.buildText("ERROR");
}
}
@Override
public DivisionChannelNotifyModel doNotify(HttpServletRequest request, Object params, List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext) {
// 响应结果
DivisionChannelNotifyModel result = new DivisionChannelNotifyModel();
try {
//配置参数获取
Byte useCert = null;
String alipaySignType, alipayPublicCert, alipayPublicKey = null;
if(mchAppConfigContext.isIsvsubMch()){
// 获取支付参数
AlipayIsvParams alipayParams = (AlipayIsvParams)configContextQueryService.queryIsvParams(mchAppConfigContext.getMchInfo().getIsvNo(), getIfCode());
useCert = alipayParams.getUseCert();
alipaySignType = alipayParams.getSignType();
alipayPublicCert = alipayParams.getAlipayPublicCert();
alipayPublicKey = alipayParams.getAlipayPublicKey();
}else{
// 获取支付参数
AlipayNormalMchParams alipayParams = (AlipayNormalMchParams)configContextQueryService.queryNormalMchParams(mchAppConfigContext.getMchNo(), mchAppConfigContext.getAppId(), getIfCode());
useCert = alipayParams.getUseCert();
alipaySignType = alipayParams.getSignType();
alipayPublicCert = alipayParams.getAlipayPublicCert();
alipayPublicKey = alipayParams.getAlipayPublicKey();
}
// 获取请求参数
JSONObject jsonParams = (JSONObject) params;
boolean verifyResult;
if(useCert != null && useCert == CS.YES){ //证书方式
verifyResult = AlipaySignature.rsaCertCheckV1(jsonParams.toJavaObject(Map.class), getCertFilePath(alipayPublicCert),
AlipayConfig.CHARSET, alipaySignType);
}else{
verifyResult = AlipaySignature.rsaCheckV1(jsonParams.toJavaObject(Map.class), alipayPublicKey, AlipayConfig.CHARSET, alipaySignType);
}
//验签失败
if(!verifyResult){
throw ResponseException.buildText("ERROR");
}
// 得到所有的 accNo 与 recordId map
Map<String, Long> accnoAndRecordIdSet = new HashMap<>();
for (PayOrderDivisionRecord record : recordList) {
accnoAndRecordIdSet.put(record.getAccNo(), record.getRecordId());
}
Map<Long, ChannelRetMsg> recordResultMap = new HashMap<>();
JSONObject bizContentJSON = jsonParams.getJSONObject("biz_content");
// 循环
JSONArray array = bizContentJSON.getJSONArray("royalty_detail_list");
for (Object o : array) {
JSONObject itemJSON = (JSONObject) o;
// 我方系统的分账接收记录ID
Long recordId = accnoAndRecordIdSet.get(itemJSON.getString("trans_in"));
// 分账类型 && 包含该笔分账账号
if("transfer".equals(itemJSON.getString("operation_type")) && recordId != null){
// 分账成功
if("SUCCESS".equals(itemJSON.getString("state"))){
recordResultMap.put(recordId, ChannelRetMsg.confirmSuccess(bizContentJSON.getString("settle_no")));
}
// 分账失败
if("FAIL".equals(itemJSON.getString("state"))){
recordResultMap.put(recordId, ChannelRetMsg.confirmFail(bizContentJSON.getString("settle_no"), itemJSON.getString("error_code"), itemJSON.getString("error_desc")));
}
}
}
result.setRecordResultMap(recordResultMap);
result.setApiRes(textResp("success"));
return result;
} catch (Exception e) {
log.error("error", e);
throw ResponseException.buildText("ERROR");
}
}
}
......@@ -136,6 +136,13 @@ public class AlipayDivisionService implements IDivisionService {
model.setOutRequestNo(recordList.get(0).getBatchOrderId()); //结算请求流水号,由商家自定义。32个字符以内,仅可包含字母、数字、下划线。需保证在商户端不重复。
model.setTradeNo(recordList.get(0).getPayOrderChannelOrderNo()); //支付宝订单号
// royalty_mode 参数说明: 同步执行 sync ; 分账异步执行 async ( 使用异步: 需要 1、请配置 支付宝应用的网关地址 ( xxx.com/api/channelbiz/alipay/appGatewayMsgReceive ), 2、 订阅消息。 )
// 2023-03-30 咨询支付宝客服: 如果没有传royalty_mode分账模式,这个默认会是同步分账,同步分账不需要关注异步通知,接口调用成功就分账成功了 2,同步分账默认不会给您发送异步通知。
// 3. 服务商代商户调用商家分账,当异步分账时服务商必须调用alipay.open.app.message.topic.subscribe(订阅消息主题)对消息api做关联绑定,服务商才会收到alipay.trade.order.settle.notify通知,否则服务商无法收到通知。
// https://opendocs.alipay.com/open/20190308105425129272/quickstart#%E8%9A%82%E8%9A%81%E6%B6%88%E6%81%AF%EF%BC%9A%E4%BA%A4%E6%98%93%E5%88%86%E8%B4%A6%E7%BB%93%E6%9E%9C%E9%80%9A%E7%9F%A5
model.setRoyaltyMode("sync"); // 综上所述, 目前使用同步调用。
//统一放置 isv接口必传信息
AlipayKit.putApiIsvInfo(mchAppConfigContext, request, model);
......@@ -152,9 +159,6 @@ public class AlipayDivisionService implements IDivisionService {
OpenApiRoyaltyDetailInfoPojo reqReceiver = new OpenApiRoyaltyDetailInfoPojo();
reqReceiver.setRoyaltyType("transfer"); //分账类型: 普通分账
// 出款信息
// reqReceiver.setTransOutType("loginName"); reqReceiver.setTransOut("xqxemt4735@sandbox.com");
// 入款信息
reqReceiver.setTransIn(record.getAccNo()); //收入方账号
reqReceiver.setTransInType("loginName");
......@@ -169,7 +173,7 @@ public class AlipayDivisionService implements IDivisionService {
}
if(reqReceiverList.isEmpty()){ // 当无分账用户时, 支付宝不允许发起分账请求, 支付宝没有完结接口,直接响应成功即可。
return ChannelRetMsg.confirmSuccess(null);
return ChannelRetMsg.confirmSuccess(null); // 明确成功。
}
model.setRoyaltyParameters(reqReceiverList); // 分账明细信息
......@@ -203,7 +207,7 @@ public class AlipayDivisionService implements IDivisionService {
return channelRetMsg;
} catch (Exception e) {
log.error("绑定支付宝账异常", e);
log.error("支付宝账异常", e);
ChannelRetMsg channelRetMsg = ChannelRetMsg.confirmFail();
channelRetMsg.setChannelErrMsg(e.getMessage());
return channelRetMsg;
......
......@@ -42,6 +42,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;
import java.math.BigDecimal;
......@@ -64,6 +65,7 @@ public class AlipayBizController extends AbstractCtrl {
@Autowired private MchAppService mchAppService;
@Autowired private IMQSender mqSender;
/** 跳转到支付宝的授权页面 (统一从pay项目获取到isv配置信息)
* isvAndMchNo 格式: ISVNO_MCHAPPID
* example: https://pay.jeepay.cn/api/channelbiz/alipay/redirectAppToAppAuth/V1623998765_60cc41694ee0e6685f57eb1f
......@@ -158,4 +160,29 @@ public class AlipayBizController extends AbstractCtrl {
return "channel/alipay/isvsubMchAuth";
}
/**
* 接收 支付宝 应用 配置中: 【应用网关地址 : 用于接收支付宝异步通知消息(例如 From蚂蚁消息等),需要传入http(s)公网可访问的网页地址。选填,若不设置,则无法接收相应的异步通知消息。】
*
* **/
@RequestMapping("/appGatewayMsgReceive")
public ModelAndView alipayAppGatewayMsgReceive() {
JSONObject reqJSON = getReqParamJSON();
// 获取到报文信息, 然后 转发到对应的ctrl
log.error("支付宝应用网关接收消息参数:{}", reqJSON);
// 分账交易通知
if("alipay.trade.order.settle.notify".equals(reqJSON.getString("msg_method"))){
// 直接转发到 分账通知的 URL去。
ModelAndView mv = new ModelAndView();
mv.setViewName("forward:/api/divisionRecordChannelNotify/" + CS.IF_CODE.ALIPAY);
return mv;
}
throw new BizException("无此事件["+ reqJSON.getString("msg_method") +"]处理器");
}
}
/*
* 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.ctrl.division;
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.exception.ResponseException;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import com.jeequan.jeepay.pay.channel.AbstractDivisionRecordChannelNotifyService;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.rqrs.msg.DivisionChannelNotifyModel;
import com.jeequan.jeepay.pay.service.ConfigContextQueryService;
import com.jeequan.jeepay.pay.service.PayOrderProcessService;
import com.jeequan.jeepay.service.impl.PayOrderDivisionRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/*
* 分账渠道侧的通知入口Controller
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2023/3/29 15:35
*/
@Slf4j
@Controller
public class DivisionRecordChannelNotifyController extends AbstractCtrl {
@Autowired private PayOrderDivisionRecordService payOrderDivisionRecordService;
@Autowired private ConfigContextQueryService configContextQueryService;
@Autowired private PayOrderProcessService payOrderProcessService;
/** 异步回调入口 **/
@ResponseBody
@RequestMapping(value= {"/api/divisionRecordChannelNotify/{ifCode}"})
public ResponseEntity doNotify(HttpServletRequest request, @PathVariable("ifCode") String ifCode){
String divisionBatchId = null;
String logPrefix = "进入[" +ifCode+ "]分账回调";
log.info("===== {} =====" , logPrefix);
try {
// 参数有误
if(StringUtils.isEmpty(ifCode)){
return ResponseEntity.badRequest().body("ifCode is empty");
}
//查询支付接口是否存在
AbstractDivisionRecordChannelNotifyService divisionNotifyService = SpringBeansUtil.getBean(ifCode + "DivisionRecordChannelNotifyService", AbstractDivisionRecordChannelNotifyService.class);
// 支付通道接口实现不存在
if(divisionNotifyService == null){
log.error("{}, interface not exists ", logPrefix);
return ResponseEntity.badRequest().body("[" + ifCode + "] interface not exists");
}
// 解析批次号 和 请求参数
MutablePair<String, Object> mutablePair = divisionNotifyService.parseParams(request);
if(mutablePair == null){ // 解析数据失败, 响应已处理
log.error("{}, mutablePair is null ", logPrefix);
throw new BizException("解析数据异常!"); //需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
//解析到订单号
divisionBatchId = mutablePair.left;
log.info("{}, 解析数据为:divisionBatchId:{}, params:{}", logPrefix, divisionBatchId, mutablePair.getRight());
// 通过 batchId 查询出列表( 注意: 需要按照ID 排序!!!! )
List<PayOrderDivisionRecord> recordList = payOrderDivisionRecordService.list(PayOrderDivisionRecord.gw()
.eq(PayOrderDivisionRecord::getState, PayOrderDivisionRecord.STATE_ACCEPT)
.eq(PayOrderDivisionRecord::getBatchOrderId, divisionBatchId)
.orderByAsc(PayOrderDivisionRecord::getRecordId)
);
// 订单不存在
if(recordList == null || recordList.isEmpty()){
log.error("{}, 待处理订单不存在. divisionBatchId={} ", logPrefix, divisionBatchId);
return divisionNotifyService.doNotifyOrderNotExists(request);
}
//查询出商户应用的配置信息
MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(recordList.get(0).getMchNo(), recordList.get(0).getAppId());
//调起接口的回调判断
DivisionChannelNotifyModel notifyResult = divisionNotifyService.doNotify(request, mutablePair.getRight(), recordList, mchAppConfigContext);
// 返回null 表明出现异常, 无需处理通知下游等操作。
if(notifyResult == null || notifyResult.getApiRes() == null){
log.error("{}, 处理回调事件异常 notifyResult data error, notifyResult ={} ",logPrefix, notifyResult);
throw new BizException("处理回调事件异常!"); //需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
if(notifyResult.getRecordResultMap() != null && !notifyResult.getRecordResultMap().isEmpty()){
for (Long divisionId : notifyResult.getRecordResultMap().keySet()) {
// 单条结果
ChannelRetMsg retMsgItem = notifyResult.getRecordResultMap().get(divisionId);
// 明确成功
if(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == retMsgItem.getChannelState()){
payOrderDivisionRecordService.updateRecordSuccessOrFailBySingleItem(divisionId, PayOrderDivisionRecord.STATE_SUCCESS, retMsgItem.getChannelOriginResponse());
} else if(ChannelRetMsg.ChannelState.CONFIRM_FAIL == retMsgItem.getChannelState()){ // 明确失败
payOrderDivisionRecordService.updateRecordSuccessOrFailBySingleItem(divisionId, PayOrderDivisionRecord.STATE_FAIL, StringUtils.defaultIfEmpty(retMsgItem.getChannelErrMsg(), retMsgItem.getChannelOriginResponse()));
}
}
}
log.info("===== {}, 通知完成。 divisionBatchId={}, parseState = {} =====", logPrefix, divisionBatchId, notifyResult);
return notifyResult.getApiRes();
} catch (BizException e) {
log.error("{}, divisionBatchId={}, BizException", logPrefix, divisionBatchId, e);
return ResponseEntity.badRequest().body(e.getMessage());
} catch (ResponseException e) {
log.error("{}, divisionBatchId={}, ResponseException", logPrefix, divisionBatchId, e);
return e.getResponseEntity();
} catch (Exception e) {
log.error("{}, divisionBatchId={}, 系统异常", logPrefix, divisionBatchId, e);
return ResponseEntity.badRequest().body(e.getMessage());
}
}
}
/*
* 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.rqrs.msg;
import lombok.Data;
import org.springframework.http.ResponseEntity;
import java.util.Map;
/***
* 封装响应结果的数据
* 直接写: MutablePair<ResponseEntity, Map<Long, ChannelRetMsg>> 太过复杂!
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2023/3/29 15:50
*/
@Data
public class DivisionChannelNotifyModel {
/** 响应接口返回的数据 **/
private ResponseEntity apiRes;
/** 每一条记录的更新状态 <ID, 结果> **/
private Map<Long, ChannelRetMsg> recordResultMap;
}
......@@ -112,7 +112,9 @@ public class PayOrderDivisionProcessService {
// 重发通知,可直接查库
if(isResend){
recordList = payOrderDivisionRecordService.list(PayOrderDivisionRecord.gw().eq(PayOrderDivisionRecord::getPayOrderId, payOrderId).eq(PayOrderDivisionRecord::getState, PayOrderDivisionRecord.STATE_FAIL));
// 根据payOrderId && 待分账( 重试时将更新为待分账状态 ) , 此处不可查询出分账成功的订单。
recordList = payOrderDivisionRecordService.list(PayOrderDivisionRecord.gw()
.eq(PayOrderDivisionRecord::getPayOrderId, payOrderId).eq(PayOrderDivisionRecord::getState, PayOrderDivisionRecord.STATE_WAIT));
}else{
// 查询&过滤 所有的分账接收对象
......
......@@ -28,6 +28,17 @@ public class PayOrderDivisionRecordService extends ServiceImpl<PayOrderDivisionR
@Autowired private PayOrderMapper payOrderMapper;
/** 更新分账记录为分账成功 ( 单条 ) 将: 已受理 更新为: 其他状态 **/
public void updateRecordSuccessOrFailBySingleItem(Long recordId, Byte state, String channelRespResult){
PayOrderDivisionRecord updateRecord = new PayOrderDivisionRecord();
updateRecord.setState(state);
updateRecord.setChannelRespResult(channelRespResult);
update(updateRecord, PayOrderDivisionRecord.gw().eq(PayOrderDivisionRecord::getRecordId, recordId).eq(PayOrderDivisionRecord::getState, PayOrderDivisionRecord.STATE_ACCEPT));
}
/** 更新分账记录为分账成功**/
public void updateRecordSuccessOrFail(List<PayOrderDivisionRecord> records, Byte state, String channelBatchOrderId, String channelRespResult){
......@@ -61,7 +72,7 @@ public class PayOrderDivisionRecordService extends ServiceImpl<PayOrderDivisionR
}
PayOrderDivisionRecord updateRecordByDiv = new PayOrderDivisionRecord();
updateRecordByDiv.setBatchOrderId(SeqKit.genDivisionBatchId()); // 重新生成batchOrderId, 避免部分失败导致: out_trade_no重复。
updateRecordByDiv.setBatchOrderId(SeqKit.genDivisionBatchId()); // 重新生成batchOrderId, 避免部分失败导致: out_trade_no重复。
updateRecordByDiv.setState(PayOrderDivisionRecord.STATE_WAIT); //待分账
updateRecordByDiv.setChannelRespResult("");
updateRecordByDiv.setChannelBatchOrderId("");
......
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