pay: 优化回调的逻辑
This commit is contained in:
parent
4390e28eea
commit
14893c4cff
@ -1,11 +1,11 @@
|
||||
package cn.iocoder.yudao.framework.pay.core.client;
|
||||
|
||||
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO;
|
||||
|
||||
/**
|
||||
@ -30,15 +30,6 @@ public interface PayClient {
|
||||
*/
|
||||
PayOrderUnifiedRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 解析支付单的通知结果
|
||||
*
|
||||
* @param data 通知结果
|
||||
* @return 解析结果
|
||||
* @throws Exception 解析失败,抛出异常
|
||||
*/
|
||||
PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception;
|
||||
|
||||
/**
|
||||
* 调用支付渠道,进行退款
|
||||
* @param reqDTO 统一退款请求信息
|
||||
@ -47,32 +38,15 @@ public interface PayClient {
|
||||
PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 解析支付退款通知数据
|
||||
* @param notifyData 支付退款通知请求数据
|
||||
* @return 支付退款通知的Notify DTO
|
||||
*/
|
||||
PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData);
|
||||
|
||||
// TODO @芋艿:后续改成非 default,避免不知道去实现
|
||||
/**
|
||||
* 验证是否渠道通知
|
||||
* 解析回调数据
|
||||
*
|
||||
* @param notifyData 通知数据
|
||||
* @return 默认是 true
|
||||
* @param rawNotify 通知内容
|
||||
* @return 回调对象
|
||||
* 1. {@link PayRefundNotifyRespDTO} 退款通知
|
||||
* 2. {@link PayOrderNotifyRespDTO} 支付通知
|
||||
*/
|
||||
default boolean verifyNotifyData(PayNotifyDataDTO notifyData) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO @芋艿:后续改成非 default,避免不知道去实现
|
||||
/**
|
||||
* 判断是否为退款通知
|
||||
*
|
||||
* @param notifyData 通知数据
|
||||
* @return 默认是 false
|
||||
*/
|
||||
default boolean isRefundNotify(PayNotifyDataDTO notifyData){
|
||||
return false;
|
||||
default Object parseNotify(PayNotifyReqDTO rawNotify) {
|
||||
throw new UnsupportedOperationException("未实现 parseNotify 方法!");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,11 +13,11 @@ import java.util.Map;
|
||||
@Data
|
||||
@ToString
|
||||
@Builder
|
||||
public class PayNotifyDataDTO {
|
||||
public class PayNotifyReqDTO {
|
||||
|
||||
|
||||
/**
|
||||
* HTTP 回调接口的 request body
|
||||
* HTTP 回调接口的 request body
|
||||
*/
|
||||
private String body;
|
||||
|
@ -35,15 +35,9 @@ public class PayOrderNotifyRespDTO {
|
||||
*/
|
||||
private LocalDateTime successTime;
|
||||
|
||||
/**
|
||||
* 通知的原始数据
|
||||
*
|
||||
* 主要用于持久化,方便后续修复数据,或者排错
|
||||
*/
|
||||
private String data;
|
||||
|
||||
/**
|
||||
* TODO @jason 结合其他的渠道定义成枚举,
|
||||
*
|
||||
* alipay
|
||||
* TRADE_CLOSED,未付款交易超时关闭,或支付完成后全额退款。
|
||||
* TRADE_SUCCESS, 交易支付成功
|
||||
|
@ -15,14 +15,13 @@ import java.time.LocalDateTime;
|
||||
@Data
|
||||
@ToString
|
||||
@Builder
|
||||
public class PayRefundNotifyDTO {
|
||||
public class PayRefundNotifyRespDTO {
|
||||
|
||||
/**
|
||||
* 支付渠道编号
|
||||
*/
|
||||
private String channelOrderNo;
|
||||
|
||||
|
||||
/**
|
||||
* 交易订单号,根据规则生成
|
||||
* 调用支付渠道时,使用该字段作为对接的订单号。
|
||||
@ -46,18 +45,14 @@ public class PayRefundNotifyDTO {
|
||||
*/
|
||||
private String reqNo;
|
||||
|
||||
|
||||
/**
|
||||
* 退款是否成功
|
||||
*/
|
||||
private PayNotifyRefundStatusEnum status;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 退款成功时间
|
||||
*/
|
||||
private LocalDateTime refundSuccessTime;
|
||||
|
||||
|
||||
}
|
@ -12,6 +12,7 @@ import com.alipay.api.AlipayResponse;import lombok.extern.slf4j.Slf4j;
|
||||
import javax.validation.Validation;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
|
||||
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_MS_FORMATTER;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
|
||||
@ -129,7 +130,12 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
|
||||
|
||||
protected String formatTime(LocalDateTime time) {
|
||||
// "yyyy-MM-dd HH:mm:ss"
|
||||
return LocalDateTimeUtil.format(time, NORM_DATETIME_MS_FORMATTER);
|
||||
return LocalDateTimeUtil.format(time, NORM_DATETIME_FORMATTER);
|
||||
}
|
||||
|
||||
protected LocalDateTime parseTime(String str) {
|
||||
// "yyyy-MM-dd HH:mm:ss"
|
||||
return LocalDateTimeUtil.parse(str, NORM_DATETIME_FORMATTER);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
|
||||
@ -20,7 +20,6 @@ import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||
@ -47,56 +46,6 @@ public abstract class AbstractAlipayClient extends AbstractPayClient<AlipayPayCl
|
||||
this.client = new DefaultAlipayClient(alipayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从支付宝通知返回参数中解析 PayOrderNotifyRespDTO, 通知具体参数参考
|
||||
* //https://opendocs.alipay.com/open/203/105286
|
||||
* @param data 通知结果
|
||||
* @return 解析结果 PayOrderNotifyRespDTO
|
||||
* @throws Exception 解析失败,抛出异常
|
||||
*/
|
||||
@Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception {
|
||||
Map<String, String> params = strToMap(data.getBody());
|
||||
|
||||
return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("out_trade_no"))
|
||||
.channelOrderNo(params.get("trade_no")).channelUserId(params.get("seller_id"))
|
||||
.tradeStatus(params.get("trade_status"))
|
||||
.successTime(LocalDateTimeUtil.parse(params.get("notify_time"), "yyyy-MM-dd HH:mm:ss"))
|
||||
.data(data.getBody()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
|
||||
Map<String, String> params = strToMap(notifyData.getBody());
|
||||
PayRefundNotifyDTO notifyDTO = PayRefundNotifyDTO.builder().channelOrderNo(params.get("trade_no"))
|
||||
.tradeNo(params.get("out_trade_no"))
|
||||
.reqNo(params.get("out_biz_no"))
|
||||
.status(PayNotifyRefundStatusEnum.SUCCESS)
|
||||
.refundSuccessTime(LocalDateTimeUtil.parse(params.get("gmt_refund"), "yyyy-MM-dd HH:mm:ss"))
|
||||
.build();
|
||||
return notifyDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefundNotify(PayNotifyDataDTO notifyData) {
|
||||
if (notifyData.getParams().containsKey("refund_fee")) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyNotifyData(PayNotifyDataDTO notifyData) {
|
||||
boolean verifyResult = false;
|
||||
try {
|
||||
verifyResult = AlipaySignature.rsaCheckV1(notifyData.getParams(), config.getAlipayPublicKey(), StandardCharsets.UTF_8.name(), "RSA2");
|
||||
} catch (AlipayApiException e) {
|
||||
log.error("[AlipayClient verifyNotifyData][(notify param is :{}) 验证失败]", toJsonString(notifyData.getParams()), e);
|
||||
}
|
||||
return verifyResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付宝统一的退款接口 alipay.trade.refund
|
||||
* @param reqDTO 退款请求 request DTO
|
||||
@ -109,7 +58,7 @@ public abstract class AbstractAlipayClient extends AbstractPayClient<AlipayPayCl
|
||||
model.setOutTradeNo(reqDTO.getPayTradeNo());
|
||||
|
||||
model.setOutRequestNo(reqDTO.getMerchantRefundId());
|
||||
model.setRefundAmount(formatAmount(reqDTO.getAmount() / 2).toString());
|
||||
model.setRefundAmount(formatAmount(reqDTO.getAmount()).toString());
|
||||
model.setRefundReason(reqDTO.getReason());
|
||||
|
||||
AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest();
|
||||
@ -138,25 +87,29 @@ public abstract class AbstractAlipayClient extends AbstractPayClient<AlipayPayCl
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付宝统一回调参数 str 转 map
|
||||
*
|
||||
* @param s 支付宝支付通知回调参数
|
||||
* @return map 支付宝集合
|
||||
*/
|
||||
public static Map<String, String> strToMap(String s) {
|
||||
// TODO @zxy:这个可以使用 hutool 的 HttpUtil decodeParams 方法么?
|
||||
Map<String, String> stringStringMap = new HashMap<>();
|
||||
// 调整时间格式
|
||||
String s3 = s.replaceAll("%3A", ":");
|
||||
// 获取 map
|
||||
String s4 = s3.replace("+", " ");
|
||||
String[] split = s4.split("&");
|
||||
for (String s1 : split) {
|
||||
String[] split1 = s1.split("=");
|
||||
stringStringMap.put(split1[0], split1[1]);
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public Object parseNotify(PayNotifyReqDTO rawNotify) {
|
||||
// 1. 校验回调数据
|
||||
String body = rawNotify.getBody();
|
||||
Map<String, String> params = rawNotify.getParams();
|
||||
Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);
|
||||
AlipaySignature.rsaCheckV1(bodyObj, config.getAlipayPublicKey(),
|
||||
StandardCharsets.UTF_8.name(), "RSA2");
|
||||
|
||||
// 2.1 退款的情况
|
||||
if (bodyObj.containsKey("refund_fee")) {
|
||||
return PayRefundNotifyRespDTO.builder().channelOrderNo(bodyObj.get("trade_no"))
|
||||
.tradeNo(bodyObj.get("out_trade_no")).reqNo(bodyObj.get("out_biz_no"))
|
||||
.status(PayNotifyRefundStatusEnum.SUCCESS)
|
||||
.refundSuccessTime(parseTime(params.get("gmt_refund")))
|
||||
.build();
|
||||
}
|
||||
return stringStringMap;
|
||||
// 2.2 支付的情况
|
||||
return PayOrderNotifyRespDTO.builder().orderExtensionNo(bodyObj.get("out_trade_no"))
|
||||
.channelOrderNo(bodyObj.get("trade_no")).channelUserId(bodyObj.get("seller_id"))
|
||||
.tradeStatus(bodyObj.get("trade_status")).successTime(parseTime(params.get("notify_time")))
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||
@ -145,8 +145,8 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
* @return 支付回调对象
|
||||
* @throws WxPayException 微信异常类
|
||||
*/
|
||||
@Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws WxPayException {
|
||||
// @Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyReqDTO data) throws WxPayException {
|
||||
log.info("[parseOrderNotify][微信支付回调data数据:{}]", data.getBody());
|
||||
// 微信支付 v2 回调结果处理
|
||||
switch (config.getApiVersion()) {
|
||||
@ -159,7 +159,7 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
}
|
||||
}
|
||||
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV3(PayNotifyDataDTO data) throws WxPayException {
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV3(PayNotifyReqDTO data) throws WxPayException {
|
||||
WxPayOrderNotifyV3Result wxPayOrderNotifyV3Result = client.parseOrderNotifyV3Result(data.getBody(), null);
|
||||
WxPayOrderNotifyV3Result.DecryptNotifyResult result = wxPayOrderNotifyV3Result.getResult();
|
||||
// 转换结果
|
||||
@ -172,11 +172,10 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
.channelOrderNo(result.getTransactionId())
|
||||
.channelUserId(result.getPayer().getOpenid())
|
||||
.successTime(LocalDateTimeUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"))
|
||||
.data(data.getBody())
|
||||
.build();
|
||||
}
|
||||
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV2(PayNotifyDataDTO data) throws WxPayException {
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV2(PayNotifyReqDTO data) throws WxPayException {
|
||||
WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data.getBody());
|
||||
Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS");
|
||||
// 转换结果
|
||||
@ -186,18 +185,10 @@ public class WXLitePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
.channelOrderNo(notifyResult.getTransactionId())
|
||||
.channelUserId(notifyResult.getOpenid())
|
||||
.successTime(LocalDateTimeUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
|
||||
.data(data.getBody())
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
|
||||
//TODO 需要实现
|
||||
throw new UnsupportedOperationException("需要实现");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
|
||||
//TODO 需要实现
|
||||
|
@ -6,9 +6,9 @@ import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||
@ -130,8 +130,8 @@ public class WXNativePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
* @return 支付回调对象
|
||||
* @throws WxPayException 微信异常类
|
||||
*/
|
||||
@Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws WxPayException {
|
||||
// @Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyReqDTO data) throws WxPayException {
|
||||
log.info("微信支付回调data数据:{}", data.getBody());
|
||||
// 微信支付 v2 回调结果处理
|
||||
switch (config.getApiVersion()) {
|
||||
@ -144,7 +144,7 @@ public class WXNativePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
}
|
||||
}
|
||||
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV3(PayNotifyDataDTO data) throws WxPayException {
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV3(PayNotifyReqDTO data) throws WxPayException {
|
||||
WxPayOrderNotifyV3Result wxPayOrderNotifyV3Result = client.parseOrderNotifyV3Result(data.getBody(), null);
|
||||
WxPayOrderNotifyV3Result.DecryptNotifyResult result = wxPayOrderNotifyV3Result.getResult();
|
||||
// 转换结果
|
||||
@ -155,11 +155,10 @@ public class WXNativePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
.orderExtensionNo(result.getOutTradeNo())
|
||||
.channelOrderNo(result.getTradeState())
|
||||
.successTime(LocalDateTimeUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"))
|
||||
.data(data.getBody())
|
||||
.build();
|
||||
}
|
||||
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV2(PayNotifyDataDTO data) throws WxPayException {
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV2(PayNotifyReqDTO data) throws WxPayException {
|
||||
WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data.getBody());
|
||||
Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS");
|
||||
// 转换结果
|
||||
@ -169,18 +168,10 @@ public class WXNativePayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
.channelOrderNo(notifyResult.getTransactionId())
|
||||
.channelUserId(notifyResult.getOpenid())
|
||||
.successTime(LocalDateTimeUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
|
||||
.data(data.getBody())
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
|
||||
// TODO 需要实现
|
||||
throw new UnsupportedOperationException("需要实现");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
|
||||
// TODO 需要实现
|
||||
|
@ -7,9 +7,8 @@ import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.io.FileUtils;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||
@ -142,8 +141,8 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
* @return 支付回调对象
|
||||
* @throws WxPayException 微信异常类
|
||||
*/
|
||||
@Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws WxPayException {
|
||||
// @Override
|
||||
public PayOrderNotifyRespDTO parseOrderNotify(PayNotifyReqDTO data) throws WxPayException {
|
||||
log.info("[parseOrderNotify][微信支付回调data数据: {}]", data.getBody());
|
||||
// 微信支付 v2 回调结果处理
|
||||
switch (config.getApiVersion()) {
|
||||
@ -156,7 +155,7 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
}
|
||||
}
|
||||
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV3(PayNotifyDataDTO data) throws WxPayException {
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV3(PayNotifyReqDTO data) throws WxPayException {
|
||||
WxPayOrderNotifyV3Result wxPayOrderNotifyV3Result = client.parseOrderNotifyV3Result(data.getBody(), null);
|
||||
WxPayOrderNotifyV3Result.DecryptNotifyResult result = wxPayOrderNotifyV3Result.getResult();
|
||||
// 转换结果
|
||||
@ -167,11 +166,10 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
.orderExtensionNo(result.getOutTradeNo())
|
||||
.channelOrderNo(result.getTradeState())
|
||||
.successTime(LocalDateTimeUtil.parse(result.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"))
|
||||
.data(data.getBody())
|
||||
.build();
|
||||
}
|
||||
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV2(PayNotifyDataDTO data) throws WxPayException {
|
||||
private PayOrderNotifyRespDTO parseOrderNotifyV2(PayNotifyReqDTO data) throws WxPayException {
|
||||
WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data.getBody());
|
||||
Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS");
|
||||
// 转换结果
|
||||
@ -181,17 +179,10 @@ public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> {
|
||||
.channelOrderNo(notifyResult.getTransactionId())
|
||||
.channelUserId(notifyResult.getOpenid())
|
||||
.successTime(LocalDateTimeUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss"))
|
||||
.data(data.getBody())
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData) {
|
||||
// TODO 需要实现
|
||||
throw new UnsupportedOperationException("需要实现");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PayRefundUnifiedRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
|
||||
// TODO 需要实现
|
||||
|
@ -6,6 +6,7 @@ package cn.iocoder.yudao.framework.pay.core.enums;
|
||||
* @author jason
|
||||
*/
|
||||
public enum PayNotifyRefundStatusEnum {
|
||||
|
||||
/**
|
||||
* 支付宝 中 全额退款 trade_status=TRADE_CLOSED, 部分退款 trade_status=TRADE_SUCCESS
|
||||
* 退款成功
|
||||
@ -17,4 +18,5 @@ public enum PayNotifyRefundStatusEnum {
|
||||
* 退款异常
|
||||
*/
|
||||
ABNORMAL;
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,11 @@ package cn.iocoder.yudao.module.pay.controller.admin.notify;
|
||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO;
|
||||
import cn.iocoder.yudao.module.pay.service.merchant.PayChannelService;
|
||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@ -17,6 +21,7 @@ import javax.annotation.security.PermitAll;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND;
|
||||
|
||||
@Tag(name = "管理后台 - 支付通知")
|
||||
@ -65,26 +70,31 @@ public class PayNotifyController {
|
||||
@OperateLog(enable = false) // 回调地址,无需记录操作日志
|
||||
public String notifyCallback(@PathVariable("channelId") Long channelId,
|
||||
@RequestParam(required = false) Map<String, String> params,
|
||||
@RequestBody(required = false) String body) throws Exception {
|
||||
// 校验支付渠道是否存在
|
||||
@RequestBody(required = false) String body) {
|
||||
log.info("[notifyCallback][channelId({}) 回调数据({}/{})]", channelId, params, body);
|
||||
// 1. 校验支付渠道是否存在
|
||||
PayClient payClient = payClientFactory.getPayClient(channelId);
|
||||
if (payClient == null) {
|
||||
log.error("[notifyCallback][渠道编号({}) 找不到对应的支付客户端]", channelId);
|
||||
throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
|
||||
}
|
||||
// 校验通知数据是否合法
|
||||
PayNotifyDataDTO notifyData = PayNotifyDataDTO.builder().params(params).body(body).build();
|
||||
payClient.verifyNotifyData(notifyData);
|
||||
|
||||
// 情况一:如果是退款,则发起退款通知
|
||||
if (payClient.isRefundNotify(notifyData)) {
|
||||
refundService.notifyPayRefund(channelId, PayNotifyDataDTO.builder().params(params).body(body).build());
|
||||
// 2. 解析通知数据
|
||||
PayNotifyReqDTO rawNotify = PayNotifyReqDTO.builder().params(params).body(body).build();
|
||||
Object notify = payClient.parseNotify(rawNotify);
|
||||
|
||||
// 3. 处理通知
|
||||
// 3.1:退款通知
|
||||
if (notify instanceof PayRefundNotifyRespDTO) {
|
||||
refundService.notifyPayRefund(channelId, (PayRefundNotifyRespDTO) notify, rawNotify);
|
||||
return "success";
|
||||
}
|
||||
|
||||
// 情况二:如果非退款,则发起支付通知
|
||||
orderService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().params(params).body(body).build());
|
||||
return "success";
|
||||
// 3.2:支付通知
|
||||
if (notify instanceof PayOrderNotifyRespDTO) {
|
||||
orderService.notifyPayOrder(channelId, (PayOrderNotifyRespDTO) notify, rawNotify);
|
||||
return "success";
|
||||
}
|
||||
throw new UnsupportedOperationException("未知通知:" + toJsonString(notify));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ package cn.iocoder.yudao.module.pay.service.order;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
|
||||
@ -93,8 +94,9 @@ public interface PayOrderService {
|
||||
* 通知支付单成功
|
||||
*
|
||||
* @param channelId 渠道编号
|
||||
* @param notifyData 通知数据
|
||||
* @param notify 通知
|
||||
* @param rawNotify 通知数据
|
||||
*/
|
||||
void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) throws Exception;
|
||||
void notifyPayOrder(Long channelId, PayOrderNotifyRespDTO notify, PayNotifyReqDTO rawNotify);
|
||||
|
||||
}
|
||||
|
@ -3,13 +3,12 @@ package cn.iocoder.yudao.module.pay.service.order;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.pay.config.PayProperties;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
|
||||
@ -45,6 +44,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.*;
|
||||
|
||||
/**
|
||||
* 支付订单 Service 实现类
|
||||
@ -105,7 +105,7 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
reqDTO.getAppId(), reqDTO.getMerchantOrderId());
|
||||
if (order != null) {
|
||||
log.warn("[createPayOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(),
|
||||
order.getMerchantOrderId(), JsonUtils.toJsonString(order)); // 理论来说,不会出现这个情况
|
||||
order.getMerchantOrderId(), toJsonString(order)); // 理论来说,不会出现这个情况
|
||||
return order.getId();
|
||||
}
|
||||
|
||||
@ -222,49 +222,30 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void notifyPayOrder(Long channelId, PayNotifyDataDTO notifyData) {
|
||||
// TODO 芋艿,记录回调日志
|
||||
log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData.getBody());
|
||||
|
||||
public void notifyPayOrder(Long channelId, PayOrderNotifyRespDTO notify, PayNotifyReqDTO rawNotify) {
|
||||
// 校验支付渠道是否有效
|
||||
PayChannelDO channel = channelService.validPayChannel(channelId);
|
||||
TenantUtils.execute(channel.getTenantId(), () -> {
|
||||
try {
|
||||
notifyPayOrder(channel, notifyData);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// 1. 更新 PayOrderExtensionDO 支付成功
|
||||
PayOrderExtensionDO orderExtension = updatePayOrderExtensionSuccess(notify.getOrderExtensionNo(),
|
||||
rawNotify);
|
||||
// 2. 更新 PayOrderDO 支付成功
|
||||
PayOrderDO order = updatePayOrderSuccess(channel, orderExtension, notify);
|
||||
|
||||
// 3. 插入支付通知记录
|
||||
notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
||||
.type(PayNotifyTypeEnum.ORDER.getType()).dataId(order.getId()).build());
|
||||
});
|
||||
}
|
||||
|
||||
private void notifyPayOrder(PayChannelDO channel, PayNotifyDataDTO notifyData) throws Exception {
|
||||
// 校验支付客户端是否正确初始化
|
||||
PayClient client = payClientFactory.getPayClient(channel.getId());
|
||||
if (client == null) {
|
||||
log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
||||
throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 0. 解析支付结果
|
||||
PayOrderNotifyRespDTO notifyRespDTO = client.parseOrderNotify(notifyData);
|
||||
// 1. 更新 PayOrderExtensionDO 支付成功
|
||||
PayOrderExtensionDO orderExtension = updatePayOrderExtensionSuccess(notifyRespDTO.getOrderExtensionNo(), notifyData.getBody());
|
||||
// 2. 更新 PayOrderDO 支付成功
|
||||
PayOrderDO order = updatePayOrderSuccess(channel, orderExtension, notifyRespDTO);
|
||||
|
||||
// 3. 插入支付通知记录
|
||||
notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
||||
.type(PayNotifyTypeEnum.ORDER.getType()).dataId(order.getId()).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 PayOrderExtensionDO 支付成功
|
||||
*
|
||||
* @param no 支付订单号(支付模块)
|
||||
* @param body 回调内容
|
||||
* @param rawNotify 通知数据
|
||||
* @return PayOrderExtensionDO 对象
|
||||
*/
|
||||
private PayOrderExtensionDO updatePayOrderExtensionSuccess(String no, String body) {
|
||||
private PayOrderExtensionDO updatePayOrderExtensionSuccess(String no, PayNotifyReqDTO rawNotify) {
|
||||
// 1.1 查询 PayOrderExtensionDO
|
||||
PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(no);
|
||||
if (orderExtension == null) {
|
||||
@ -276,7 +257,8 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
// 1.2 更新 PayOrderExtensionDO
|
||||
int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(),
|
||||
PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId())
|
||||
.status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(body).build());
|
||||
.status(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||
.channelNotifyData(toJsonString(rawNotify)).build());
|
||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||
throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||
}
|
||||
@ -289,11 +271,11 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
*
|
||||
* @param channel 支付渠道
|
||||
* @param orderExtension 支付拓展单
|
||||
* @param notifyRespDTO 通知回调
|
||||
* @param notify 通知回调
|
||||
* @return PayOrderDO 对象
|
||||
*/
|
||||
private PayOrderDO updatePayOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
|
||||
PayOrderNotifyRespDTO notifyRespDTO) {
|
||||
PayOrderNotifyRespDTO notify) {
|
||||
// 2.1 判断 PayOrderDO 是否处于待支付
|
||||
PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
|
||||
if (order == null) {
|
||||
@ -306,8 +288,8 @@ public class PayOrderServiceImpl implements PayOrderService {
|
||||
int updateCounts = orderMapper.updateByIdAndStatus(order.getId(), PayOrderStatusEnum.WAITING.getStatus(),
|
||||
PayOrderDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||
.channelId(channel.getId()).channelCode(channel.getCode())
|
||||
.successTime(notifyRespDTO.getSuccessTime()).successExtensionId(orderExtension.getId())
|
||||
.channelOrderNo(notifyRespDTO.getChannelOrderNo()).channelUserId(notifyRespDTO.getChannelUserId())
|
||||
.successTime(notify.getSuccessTime()).successExtensionId(orderExtension.getId())
|
||||
.channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
|
||||
.notifyTime(LocalDateTime.now()).build());
|
||||
if (updateCounts == 0) { // 校验状态,必须是待支付
|
||||
throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.pay.service.refund;
|
||||
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO;
|
||||
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
||||
@ -52,9 +53,9 @@ public interface PayRefundService {
|
||||
* 渠道的退款通知
|
||||
*
|
||||
* @param channelId 渠道编号
|
||||
* @param notifyData 通知数据
|
||||
* @throws Exception 退款通知异常
|
||||
* @param notify 通知
|
||||
* @param rawNotify 通知数据
|
||||
*/
|
||||
void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) throws Exception;
|
||||
void notifyPayRefund(Long channelId, PayRefundNotifyRespDTO notify, PayNotifyReqDTO rawNotify);
|
||||
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.pay.config.PayProperties;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||
import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
|
||||
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
||||
@ -187,29 +187,22 @@ public class PayRefundServiceImpl implements PayRefundService {
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) {
|
||||
log.info("[notifyPayRefund][channelId({}) 回调数据({})]", channelId, notifyData.getBody());
|
||||
public void notifyPayRefund(Long channelId, PayRefundNotifyRespDTO notify, PayNotifyReqDTO rawNotify) {
|
||||
// 校验支付渠道是否有效
|
||||
// TODO 芋艿:需要重构下这块的逻辑
|
||||
PayChannelDO channel = channelService.validPayChannel(channelId);
|
||||
// 校验支付客户端是否正确初始化
|
||||
PayClient client = payClientFactory.getPayClient(channel.getId());
|
||||
if (client == null) {
|
||||
log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
|
||||
}
|
||||
// 解析渠道退款通知数据, 统一处理
|
||||
PayRefundNotifyDTO refundNotify = client.parseRefundNotify(notifyData);
|
||||
if (Objects.equals(PayNotifyRefundStatusEnum.SUCCESS,refundNotify.getStatus())){
|
||||
payRefundSuccess(refundNotify);
|
||||
if (Objects.equals(PayNotifyRefundStatusEnum.SUCCESS, notify.getStatus())){
|
||||
payRefundSuccess(notify);
|
||||
} else {
|
||||
//TODO 支付异常, 支付宝似乎没有支付异常的通知。
|
||||
// TODO @jason:那这里可以考虑打个 error logger @芋艿 微信是否存在支付异常通知
|
||||
}
|
||||
}
|
||||
|
||||
private void payRefundSuccess(PayRefundNotifyDTO refundNotify) {
|
||||
private void payRefundSuccess(PayRefundNotifyRespDTO refundNotify) {
|
||||
// 校验退款单存在
|
||||
PayRefundDO refundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(refundNotify.getTradeNo(), refundNotify.getReqNo());
|
||||
PayRefundDO refundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(refundNotify.getTradeNo(),
|
||||
refundNotify.getReqNo());
|
||||
if (refundDO == null) {
|
||||
log.error("[payRefundSuccess][不存在 seqNo 为{} 的支付退款单]", refundNotify.getReqNo());
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_NOT_FOUND);
|
||||
|
@ -1,79 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
|
||||
<title>支付测试页</title>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
|
||||
<script src="qrcode.min.js" type="text/javascript"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>点击如下按钮,发起支付宝扫码支付的测试</div>
|
||||
<div>
|
||||
<button id="alipay_wap">支付宝扫码支付</button>
|
||||
</div>
|
||||
<div id="qrcode"></div>
|
||||
</body>
|
||||
<style>
|
||||
#qrcode{
|
||||
padding-left: 20px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
let shopOrderId = undefined;
|
||||
let payOrderId = undefined;
|
||||
let server = 'http://127.0.0.1:48080';
|
||||
$(function() {
|
||||
// 自动发起商城订单编号
|
||||
$.ajax({
|
||||
url: server + "/app-api/shop/order/create",
|
||||
method: 'POST',
|
||||
success: function( result ) {
|
||||
if (result.code !== 0) {
|
||||
alert('创建商城订单失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
shopOrderId = result.data.id;
|
||||
payOrderId = result.data.payOrderId;
|
||||
console.log("商城订单:" + shopOrderId)
|
||||
console.log("支付订单:" + payOrderId)
|
||||
}
|
||||
})
|
||||
});
|
||||
// 支付宝扫码支付
|
||||
$( "#alipay_wap").on( "click", function() {
|
||||
// 提交支付
|
||||
$.ajax({
|
||||
url: server + "/app-api/pay/order/submit",
|
||||
method: 'POST',
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify({
|
||||
"id": payOrderId,
|
||||
"channelCode": 'alipay_qr'
|
||||
}),
|
||||
success: function( result ) {
|
||||
if (result.code !== 0) {
|
||||
alert('提交支付订单失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
//提交支付后返回的参数
|
||||
let data = result.data.invokeResponse;
|
||||
new QRCode($("#qrcode")[0],{
|
||||
text: data.qrCode, //内容
|
||||
width:98, //宽度
|
||||
height:98, //高度
|
||||
correctLevel: 3,//二维码纠错级别
|
||||
background: "#ffffff",//背景颜色
|
||||
foreground: "#000000"//二维码颜色
|
||||
});
|
||||
|
||||
console.log("data.qrCode===",data.qrCode)
|
||||
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</html>
|
@ -1,65 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
|
||||
<title>支付测试页</title>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>点击如下按钮,发起支付的测试</div>
|
||||
<div>
|
||||
<button id="alipay_wap">支付宝手机网站支付</button>
|
||||
</div>
|
||||
<div id="dynamic_form"></div>
|
||||
</body>
|
||||
<script>
|
||||
|
||||
let shopOrderId = undefined;
|
||||
let payOrderId = undefined;
|
||||
let server = 'http://127.0.0.1:48080';
|
||||
//let server = 'http://niubi.natapp1.cc';
|
||||
|
||||
$(function() {
|
||||
// 自动发起商城订单编号
|
||||
$.ajax({
|
||||
url: server + "/app-api/shop/order/create",
|
||||
method: 'POST',
|
||||
success: function( result ) {
|
||||
if (result.code !== 0) {
|
||||
alert('创建商城订单失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
shopOrderId = result.data.id;
|
||||
payOrderId = result.data.payOrderId;
|
||||
console.log("商城订单:" + shopOrderId)
|
||||
console.log("支付订单:" + payOrderId)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
$( "#alipay_wap").on( "click", function() {
|
||||
// 提交支付
|
||||
$.ajax({
|
||||
url: server + "/app-api/pay/order/submit",
|
||||
method: 'POST',
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify({
|
||||
"id": payOrderId,
|
||||
"channelCode": 'alipay_wap'
|
||||
}),
|
||||
success: function( result ) {
|
||||
if (result.code !== 0) {
|
||||
alert('提交支付订单失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert('点击确定,开始支付');
|
||||
//支付宝 手机WAP 返回表单,自动跳到支付宝支付页面
|
||||
let data = result.data.invokeResponse;
|
||||
$("#dynamic_form").html(data.body);
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
@ -1,38 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
|
||||
<title>社交登陆测试页</title>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>点击如下按钮,发起登陆的测试</div>
|
||||
<div>
|
||||
<button id="wx_pub">微信公众号</button>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
// let server = 'http://127.0.0.1:28080';
|
||||
let server = 'http://192.168.1.2:48080';
|
||||
|
||||
|
||||
// 微信公众号
|
||||
$( "#wx_pub").on( "click", function() {
|
||||
// 获得授权链接
|
||||
$.ajax({
|
||||
url: server + "/app-api/social-auth-redirect?type=31&redirectUri=" +
|
||||
encodeURIComponent(server + '/static/social-login2.html'), //重定向地址
|
||||
method: 'GET',
|
||||
success: function( result ) {
|
||||
if (result.code !== 0) {
|
||||
alert('获得授权链接失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
// 跳转重定向
|
||||
document.location.href = result.data;
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</html>
|
@ -1,87 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
|
||||
<title>社交登陆测试页</title>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>点击如下按钮,授权登录</div>
|
||||
<div>
|
||||
手机号<input id="mobile" value="15601691300"><br>
|
||||
手机验证码<input id="smsCode">
|
||||
<button id="send_sms_code">发送手机验证码</button>
|
||||
<br>
|
||||
<button id="wx_pub">微信公众号授权登录</button>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
// let server = 'http://127.0.0.1:48080';
|
||||
let server = 'http://192.168.1.2:48080';
|
||||
|
||||
let type = 31; //登录类型 微信公众号
|
||||
|
||||
// 微信公众号
|
||||
$("#wx_pub").on("click", function () {
|
||||
let code = getUrlParam("code"); // 访问授权连接后,会回调本页面地址,参数在本页面url后面
|
||||
let state = getUrlParam("state");
|
||||
console.log("获取code: " + code + ", state: " + state)
|
||||
|
||||
let data = {
|
||||
'mobile': $('#mobile').val(),
|
||||
'smsCode': $('#smsCode').val(),
|
||||
'code': code,
|
||||
'state': state,
|
||||
'type': type
|
||||
}
|
||||
|
||||
// 调用授权登录接口
|
||||
$.ajax({
|
||||
url: server + "/app-api/social-login2",
|
||||
method: 'POST',
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json;charset=utf-8",
|
||||
dataType: "json",
|
||||
success: function( result ) {
|
||||
if (result.code !== 0) {
|
||||
alert('调用授权登录接口失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert("授权登录成功, token: "+result.data.token)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// 发送手机验证码
|
||||
$("#send_sms_code").on("click", function () {
|
||||
let data = {
|
||||
'mobile': $('#mobile').val(),
|
||||
'scene': 1 // 手机号登陆 类型
|
||||
}
|
||||
$.ajax({
|
||||
url: server + "/app-api/send-sms-code",
|
||||
method: 'POST',
|
||||
data: JSON.stringify(data),
|
||||
contentType: "application/json;charset=utf-8",
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
if (result.code !== 0) {
|
||||
alert('发送手机验证码失败,原因:' + result.msg)
|
||||
return;
|
||||
}
|
||||
alert("发送成功, 请查看日志");
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
//获取url中的参数
|
||||
function getUrlParam(name) {
|
||||
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
|
||||
var r = window.location.search.substr(1).match(reg); //匹配目标参数
|
||||
if (r != null) return unescape(r[2]);
|
||||
return null; //返回参数值
|
||||
}
|
||||
</script>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user