Commit 0bbd04d0 authored by dingzhiwei's avatar dingzhiwei
Browse files

增加退款回调处理逻辑&优化小新支付退款处理

parent 7663b202
/*
* 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.pay.util.ChannelCertConfigKitBean;
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;
/*
* 实现退款回调接口抽象类
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/25 23:18
*/
public abstract class AbstractChannelRefundNoticeService implements IChannelRefundNoticeService {
@Autowired private RequestKitBean requestKitBean;
@Autowired private ChannelCertConfigKitBean channelCertConfigKitBean;
@Override
public ResponseEntity doNotifyOrderNotExists(HttpServletRequest request) {
return textResp("order not exists");
}
@Override
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);
}
}
......@@ -36,8 +36,8 @@ public abstract class AbstractRefundService implements IRefundService{
return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/refund/notify/" + getIfCode();
}
protected String getNotifyUrl(String payOrderId){
return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/refund/notify/" + getIfCode() + "/" + payOrderId;
protected String getNotifyUrl(String refundOrderId){
return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/refund/notify/" + getIfCode() + "/" + refundOrderId;
}
}
......@@ -24,7 +24,7 @@ import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
/*
* 渠道侧的通知解析实现 【分为同步跳转(doReturn)和异步回调(doNotify) 】
* 渠道侧的支付订单通知解析实现 【分为同步跳转(doReturn)和异步回调(doNotify) 】
*
* @author terrfly
* @site https://www.jeequan.com
......
/*
* 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.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.RefundOrder;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.http.ResponseEntity;
import javax.servlet.http.HttpServletRequest;
/*
* 渠道侧的退款订单通知解析实现 【分为同步跳转(doReturn)和异步回调(doNotify) 】
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/25 23:14
*/
public interface IChannelRefundNoticeService {
/** 通知类型 **/
enum NoticeTypeEnum {
DO_NOTIFY //异步回调
}
/** 获取到接口code **/
String getIfCode();
/** 解析参数: 订单号 和 请求参数
* 异常需要自行捕捉,并返回null , 表示已响应数据。
* **/
MutablePair<String, Object> parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum);
/** 返回需要更新的订单状态 和响应数据 **/
ChannelRetMsg doNotice(HttpServletRequest request,
Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum);
/** 数据库订单 状态更新异常 (仅异步通知使用) **/
ResponseEntity doNotifyOrderStateUpdateFail(HttpServletRequest request);
/** 数据库订单数据不存在 (仅异步通知使用) **/
ResponseEntity doNotifyOrderNotExists(HttpServletRequest request);
}
......@@ -31,7 +31,7 @@ import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
/*
* 小新支付 回调接口实现类
* 小新支付 支付回调接口实现类
*
* @author jmdhappy
* @site https://www.jeequan.com
......
/*
* 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.xxpay;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.RefundOrder;
import com.jeequan.jeepay.core.exception.ResponseException;
import com.jeequan.jeepay.core.model.params.xxpay.XxpayNormalMchParams;
import com.jeequan.jeepay.pay.channel.AbstractChannelRefundNoticeService;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
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;
/*
* 小新支付 退款回调接口实现类
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/21 00:16
*/
@Service
@Slf4j
public class XxpayChannelRefundNoticeService extends AbstractChannelRefundNoticeService {
@Override
public String getIfCode() {
return CS.IF_CODE.XXPAY;
}
@Override
public MutablePair<String, Object> parseParams(HttpServletRequest request, String urlOrderId, NoticeTypeEnum noticeTypeEnum) {
try {
JSONObject params = getReqParamJSON();
String refundOrderId = params.getString("mchRefundNo");
return MutablePair.of(refundOrderId, params);
} catch (Exception e) {
log.error("error", e);
throw ResponseException.buildText("ERROR");
}
}
@Override
public ChannelRetMsg doNotice(HttpServletRequest request, Object params, RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext, NoticeTypeEnum noticeTypeEnum) {
try {
XxpayNormalMchParams xxpayParams = mchAppConfigContext.getNormalMchParamsByIfCode(getIfCode(), XxpayNormalMchParams.class);
// 获取请求参数
JSONObject jsonParams = (JSONObject) params;
String checkSign = jsonParams.getString("sign");
jsonParams.remove("sign");
// 验证签名
if(!checkSign.equals(XxpayKit.getSign(jsonParams, xxpayParams.getKey()))) {
throw ResponseException.buildText("ERROR");
}
//验签成功后判断上游订单状态
ResponseEntity okResponse = textResp("success");
// 支付状态,0-订单生成,1-支付中,2-支付成功,3-业务处理完成
String status = jsonParams.getString("status");
ChannelRetMsg result = new ChannelRetMsg();
result.setChannelOrderId(jsonParams.getString("channelOrderNo")); //渠道订单号
result.setResponseEntity(okResponse); //响应数据
result.setChannelState(ChannelRetMsg.ChannelState.WAITING); // 默认支付中
if("2".equals(status) || "3".equals(status)){
result.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
}
return result;
} catch (Exception e) {
log.error("error", e);
throw ResponseException.buildText("ERROR");
}
}
}
......@@ -50,7 +50,6 @@ public class XxpayPayOrderQueryService implements IPayOrderQueryService {
@Override
public ChannelRetMsg query(PayOrder payOrder, MchAppConfigContext mchAppConfigContext){
XxpayNormalMchParams xxpayParams = mchAppConfigContext.getNormalMchParamsByIfCode(getIfCode(), XxpayNormalMchParams.class);
String queryPayOrderUrl = XxpayKit.getQueryPayOrderUrl(xxpayParams.getPayUrl());
Map<String,Object> paramMap = new TreeMap();
// 接口类型
paramMap.put("mchId", xxpayParams.getMchId());
......@@ -58,8 +57,11 @@ public class XxpayPayOrderQueryService implements IPayOrderQueryService {
String sign = XxpayKit.getSign(paramMap, xxpayParams.getKey());
paramMap.put("sign", sign);
String resStr = "";
String queryPayOrderUrl = XxpayKit.getQueryPayOrderUrl(xxpayParams.getPayUrl()) + "?" + JeepayKit.genUrlParams(paramMap);
try {
resStr = HttpUtil.createPost(queryPayOrderUrl + "?" + JeepayKit.genUrlParams(paramMap)).timeout(60 * 1000).execute().body();
log.info("支付查询[{}]参数:{}", getIfCode(), queryPayOrderUrl);
resStr = HttpUtil.createPost(queryPayOrderUrl).timeout(60 * 1000).execute().body();
log.info("支付查询[{}]结果:{}", getIfCode(), resStr);
} catch (Exception e) {
log.error("http error", e);
}
......
......@@ -81,9 +81,9 @@ public class XxpayPaymentService extends AbstractPaymentService {
String payUrl = XxpayKit.getPaymentUrl(params.getPayUrl())+ "?" + JeepayKit.genUrlParams(paramMap);
String resStr = "";
try {
log.info("请求{}参数:{}", getIfCode(), payUrl);
log.info("发起支付[{}]参数:{}", getIfCode(), payUrl);
resStr = HttpUtil.createPost(payUrl).timeout(60 * 1000).execute().body();
log.info("请求{}结果:{}", getIfCode(), resStr);
log.info("发起支付[{}]结果:{}", getIfCode(), resStr);
} catch (Exception e) {
log.error("http error", e);
}
......
/*
* 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.xxpay;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.RefundOrder;
import com.jeequan.jeepay.core.model.params.xxpay.XxpayNormalMchParams;
import com.jeequan.jeepay.core.utils.JeepayKit;
import com.jeequan.jeepay.pay.channel.AbstractRefundService;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.rqrs.refund.RefundOrderRQ;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.TreeMap;
/*
* 退款接口: 小新支付
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/26 9:38
*/
@Service
@Slf4j
public class XxpayRefundService extends AbstractRefundService {
@Override
public String getIfCode() {
return CS.IF_CODE.XXPAY;
}
@Override
public String preCheck(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder) {
return null;
}
@Override
public ChannelRetMsg refund(RefundOrderRQ bizRQ, RefundOrder refundOrder, PayOrder payOrder, MchAppConfigContext mchAppConfigContext) throws Exception {
XxpayNormalMchParams params = mchAppConfigContext.getNormalMchParamsByIfCode(getIfCode(), XxpayNormalMchParams.class);
// 构造支付请求参数
Map<String,Object> paramMap = new TreeMap();
paramMap.put("mchId", params.getMchId()); //商户ID
paramMap.put("mchOrderNo", refundOrder.getPayOrderId()); //支付订单-商户订单号
paramMap.put("mchRefundNo", refundOrder.getRefundOrderId()); //商户退款单号
paramMap.put("amount", refundOrder.getRefundAmount()); //退款金额
paramMap.put("currency", "cny"); //币种
paramMap.put("clientIp", refundOrder.getClientIp()); //客户端IP
paramMap.put("device", "web"); //客户端设备
//如果notifyUrl 不为空表示异步退款,具体退款结果以退款通知为准
paramMap.put("notifyUrl", getNotifyUrl(refundOrder.getRefundOrderId())); // 异步退款通知
paramMap.put("remarkInfo", refundOrder.getRefundReason()); // 退款原因
// 生成签名
String sign = XxpayKit.getSign(paramMap, params.getKey());
paramMap.put("sign", sign);
// 退款地址
String refundUrl = XxpayKit.getRefundUrl(params.getPayUrl())+ "?" + JeepayKit.genUrlParams(paramMap);
String resStr = "";
try {
log.info("发起退款[{}]参数:{}", getIfCode(), refundUrl);
resStr = HttpUtil.createPost(refundUrl).timeout(60 * 1000).execute().body();
log.info("发起退款[{}]结果:{}", getIfCode(), resStr);
} catch (Exception e) {
log.error("http error", e);
}
ChannelRetMsg channelRetMsg = new ChannelRetMsg();
// 默认退款中状态
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING);
if(StringUtils.isEmpty(resStr)) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
channelRetMsg.setChannelErrCode("");
channelRetMsg.setChannelErrMsg("请求"+getIfCode()+"接口异常");
return null;
}
JSONObject resObj = JSONObject.parseObject(resStr);
if(!"0".equals(resObj.getString("retCode"))){
String retMsg = resObj.getString("retMsg");
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
channelRetMsg.setChannelErrCode("");
channelRetMsg.setChannelErrMsg(retMsg);
return null;
}
// 验证响应数据签名
String checkSign = resObj.getString("sign");
resObj.remove("sign");
if(!checkSign.equals(XxpayKit.getSign(resObj, params.getKey()))) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
return null;
}
// 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败
String status = resObj.getString("status");
if("2".equals(status)) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
}else if("3".equals(status)) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
channelRetMsg.setChannelErrMsg(resObj.getString("retMsg"));
}
return channelRetMsg;
}
@Override
public ChannelRetMsg query(RefundOrder refundOrder, MchAppConfigContext mchAppConfigContext) throws Exception {
XxpayNormalMchParams params = mchAppConfigContext.getNormalMchParamsByIfCode(getIfCode(), XxpayNormalMchParams.class);
// 构造支付请求参数
Map<String,Object> paramMap = new TreeMap();
paramMap.put("mchId", params.getMchId()); //商户ID
paramMap.put("mchRefundNo", refundOrder.getRefundOrderId()); //商户退款单号
// 生成签名
String sign = XxpayKit.getSign(paramMap, params.getKey());
paramMap.put("sign", sign);
// 退款查询地址
String queryRefundOrderUrl = XxpayKit.getQueryRefundOrderUrl(params.getPayUrl())+ "?" + JeepayKit.genUrlParams(paramMap);
String resStr = "";
try {
log.info("查询退款[{}]参数:{}", getIfCode(), queryRefundOrderUrl);
resStr = HttpUtil.createPost(queryRefundOrderUrl).timeout(60 * 1000).execute().body();
log.info("查询退款[{}]结果:{}", getIfCode(), resStr);
} catch (Exception e) {
log.error("http error", e);
}
ChannelRetMsg channelRetMsg = new ChannelRetMsg();
// 默认退款中状态
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING);
if(StringUtils.isEmpty(resStr)) {
return null;
}
JSONObject resObj = JSONObject.parseObject(resStr);
if(!"0".equals(resObj.getString("retCode"))){
return null;
}
// 验证响应数据签名
String checkSign = resObj.getString("sign");
resObj.remove("sign");
if(!checkSign.equals(XxpayKit.getSign(resObj, params.getKey()))) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
return null;
}
// 退款状态:0-订单生成,1-退款中,2-退款成功,3-退款失败
String status = resObj.getString("status");
if("2".equals(status)) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_SUCCESS);
}else if("3".equals(status)) {
channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
channelRetMsg.setChannelErrMsg(resObj.getString("retMsg"));
}
return channelRetMsg;
}
}
/*
* 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.refund;
import com.jeequan.jeepay.core.ctrls.AbstractCtrl;
import com.jeequan.jeepay.core.entity.RefundOrder;
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.IChannelRefundNoticeService;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.pay.service.ConfigContextService;
import com.jeequan.jeepay.pay.service.RefundOrderProcessService;
import com.jeequan.jeepay.service.impl.RefundOrderService;
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;
/*
* 渠道侧的退款通知入口Controller 【异步回调(doNotify) 】
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/25 22:35
*/
@Slf4j
@Controller
public class ChannelRefundNoticeController extends AbstractCtrl {
@Autowired private RefundOrderService refundOrderService;
@Autowired private ConfigContextService configContextService;
@Autowired private RefundOrderProcessService refundOrderProcessService;
/** 异步回调入口 **/
@ResponseBody
@RequestMapping(value= {"/api/refund/notify/{ifCode}", "/api/refund/notify/{ifCode}/{refundOrderId}"})
public ResponseEntity doNotify(HttpServletRequest request, @PathVariable("ifCode") String ifCode, @PathVariable(value = "refundOrderId", required = false) String urlOrderId){
String refundOrderId = null;
String logPrefix = "进入[" +ifCode+ "]退款回调:urlOrderId:["+ StringUtils.defaultIfEmpty(urlOrderId, "") + "] ";
log.info("===== {} =====" , logPrefix);
try {
// 参数有误
if(StringUtils.isEmpty(ifCode)){
return ResponseEntity.badRequest().body("ifCode is empty");
}
//查询退款接口是否存在
IChannelRefundNoticeService refundNotifyService = SpringBeansUtil.getBean(ifCode + "ChannelRefundNoticeService", IChannelRefundNoticeService.class);
// 支付通道接口实现不存在
if(refundNotifyService == null){
log.error("{}, interface not exists ", logPrefix);
return ResponseEntity.badRequest().body("[" + ifCode + "] interface not exists");
}
// 解析订单号 和 请求参数
MutablePair<String, Object> mutablePair = refundNotifyService.parseParams(request, urlOrderId, IChannelRefundNoticeService.NoticeTypeEnum.DO_NOTIFY);
if(mutablePair == null){ // 解析数据失败, 响应已处理
log.error("{}, mutablePair is null ", logPrefix);
throw new BizException("解析数据异常!"); //需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
// 解析到订单号
refundOrderId = mutablePair.left;
log.info("{}, 解析数据为:refundOrderId:{}, params:{}", logPrefix, refundOrderId, mutablePair.getRight());
if(StringUtils.isNotEmpty(urlOrderId) && !urlOrderId.equals(refundOrderId)){
log.error("{}, 订单号不匹配. urlOrderId={}, refundOrderId={} ", logPrefix, urlOrderId, refundOrderId);
throw new BizException("退款单号不匹配!");
}
//获取订单号 和 订单数据
RefundOrder refundOrder = refundOrderService.getById(refundOrderId);
// 订单不存在
if(refundOrder == null){
log.error("{}, 退款订单不存在. refundOrder={} ", logPrefix, refundOrder);
return refundNotifyService.doNotifyOrderNotExists(request);
}
//查询出商户应用的配置信息
MchAppConfigContext mchAppConfigContext = configContextService.getMchAppConfigContext(refundOrder.getMchNo(), refundOrder.getAppId());
//调起接口的回调判断
ChannelRetMsg notifyResult = refundNotifyService.doNotice(request, mutablePair.getRight(), refundOrder, mchAppConfigContext, IChannelRefundNoticeService.NoticeTypeEnum.DO_NOTIFY);
// 返回null 表明出现异常, 无需处理通知下游等操作。
if(notifyResult == null || notifyResult.getChannelState() == null || notifyResult.getResponseEntity() == null){
log.error("{}, 处理回调事件异常 notifyResult data error, notifyResult ={} ",logPrefix, notifyResult);
throw new BizException("处理回调事件异常!"); //需要实现类自行抛出ResponseException, 不应该在这抛此异常。
}
// 处理退款订单
boolean updateOrderSuccess = refundOrderProcessService.handleRefundOrder4Channel(notifyResult, refundOrder);
// 更新退款订单 异常
if(!updateOrderSuccess){
log.error("{}, updateOrderSuccess = {} ",logPrefix, updateOrderSuccess);
return refundNotifyService.doNotifyOrderStateUpdateFail(request);
}
log.info("===== {}, 订单通知完成。 refundOrderId={}, parseState = {} =====", logPrefix, refundOrderId, notifyResult.getChannelState());
return notifyResult.getResponseEntity();
} catch (BizException e) {
log.error("{}, refundOrderId={}, BizException", logPrefix, refundOrderId, e);
return ResponseEntity.badRequest().body(e.getMessage());
} catch (ResponseException e) {
log.error("{}, refundOrderId={}, ResponseException", logPrefix, refundOrderId, e);
return e.getResponseEntity();
} catch (Exception e) {
log.error("{}, refundOrderId={}, 系统异常", logPrefix, refundOrderId, e);
return ResponseEntity.badRequest().body(e.getMessage());
}
}
}
......@@ -46,6 +46,7 @@ public class ChannelOrderReissueService {
@Autowired private RefundOrderService refundOrderService;
@Autowired private PayOrderProcessService payOrderProcessService;
@Autowired private PayMchNotifyService payMchNotifyService;
@Autowired private RefundOrderProcessService refundOrderProcessService;
/** 处理订单 **/
......@@ -124,28 +125,8 @@ public class ChannelOrderReissueService {
}
log.info("退款补单:[{}]查询结果为:{}", refundOrderId, channelRetMsg);
// 查询成功
if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS) {
if (refundOrderService.updateIng2Success(refundOrderId, channelRetMsg.getChannelOrderId())) {
// 通知商户系统
if(StringUtils.isNotEmpty(refundOrder.getNotifyUrl())){
payMchNotifyService.refundOrderNotify(refundOrderService.getById(refundOrderId));
}
}
}else if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_FAIL){ //确认失败
//1. 更新支付订单表为失败状态
refundOrderService.updateIng2Fail(refundOrderId, channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelErrCode(), channelRetMsg.getChannelErrMsg());
// 通知商户系统
if(StringUtils.isNotEmpty(refundOrder.getNotifyUrl())){
payMchNotifyService.refundOrderNotify(refundOrderService.getById(refundOrderId));
}
}
// 根据渠道返回结果,处理退款订单
refundOrderProcessService.handleRefundOrder4Channel(channelRetMsg, refundOrder);
return channelRetMsg;
......
/*
* 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.RefundOrder;
import com.jeequan.jeepay.pay.rqrs.msg.ChannelRetMsg;
import com.jeequan.jeepay.service.impl.RefundOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/***
* 退款处理通用逻辑
*
* @author jmdhappy
* @site https://www.jeequan.com
* @date 2021/9/25 23:50
*/
@Service
@Slf4j
public class RefundOrderProcessService {
@Autowired private RefundOrderService refundOrderService;
@Autowired private PayMchNotifyService payMchNotifyService;
/** 根据通道返回的状态,处理退款订单业务 **/
public boolean handleRefundOrder4Channel(ChannelRetMsg channelRetMsg, RefundOrder refundOrder){
boolean updateOrderSuccess = true; //默认更新成功
String refundOrderId = refundOrder.getRefundOrderId();
// 明确退款成功
if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_SUCCESS) {
updateOrderSuccess = refundOrderService.updateIng2Success(refundOrderId, channelRetMsg.getChannelOrderId());
if (updateOrderSuccess) {
// 通知商户系统
if(StringUtils.isNotEmpty(refundOrder.getNotifyUrl())){
payMchNotifyService.refundOrderNotify(refundOrderService.getById(refundOrderId));
}
}
//确认失败
}else if(channelRetMsg.getChannelState() == ChannelRetMsg.ChannelState.CONFIRM_FAIL){
// 更新为失败状态
updateOrderSuccess = refundOrderService.updateIng2Fail(refundOrderId, channelRetMsg.getChannelOrderId(), channelRetMsg.getChannelErrCode(), channelRetMsg.getChannelErrMsg());
// 通知商户系统
if(StringUtils.isNotEmpty(refundOrder.getNotifyUrl())){
payMchNotifyService.refundOrderNotify(refundOrderService.getById(refundOrderId));
}
}
return updateOrderSuccess;
}
}
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